From f5f99e34e4f0a64de71a4a6bf8c9406f6713c65e Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 2 May 2011 18:30:19 -0400 Subject: [PATCH 01/29] added basic mineral overlay right now, it only highlights diamond ore --- setup.py | 2 +- src/overviewer.h | 2 +- src/rendermode-mineral.c | 104 +++++++++++++++++++++++++++++++++++++++ src/rendermodes.c | 1 + src/rendermodes.h | 7 +++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/rendermode-mineral.c diff --git a/setup.py b/setup.py index 497b5ac..284795d 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ except: pil_include = [] # used to figure out what files to compile -render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave'] +render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave', 'mineral'] c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c'] c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes) diff --git a/src/overviewer.h b/src/overviewer.h index 55243a5..05f657c 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 5 +#define OVERVIEWER_EXTENSION_VERSION 6 /* Python PIL, and numpy headers */ #include diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c new file mode 100644 index 0000000..a45bbf2 --- /dev/null +++ b/src/rendermode-mineral.c @@ -0,0 +1,104 @@ +/* + * This file is part of the Minecraft Overviewer. + * + * Minecraft Overviewer is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Minecraft Overviewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the Overviewer. If not, see . + */ + +#include "overviewer.h" + +struct OreColor { + unsigned char blockid; + unsigned char r, g, b, a; +}; + +/* put more valuable ores first -- they take precedence */ +static struct OreColor orecolors[] = { + {56 /* Diamond Ore */, 32, 230, 220, 200}, + + /* end of list marker */ + {0, 0, 0, 0, 0} +}; + +static void get_color(void *data, RenderState *state, + unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { + + int x = state->x, y = state->y, z_max = state->z, z; + //RenderModeMineral* self = (RenderModeMineral *)data; + *a = 0; + + for (z = 0; z <= z_max; z++) { + int i, max_i = sizeof(orecolors) / sizeof(struct OreColor); + unsigned char blockid = getArrayByte3D(state->blocks, x, y, z); + + for (i = 0; i < max_i && orecolors[i].blockid != 0; i++) { + if (orecolors[i].blockid == blockid) { + *r = orecolors[i].r; + *g = orecolors[i].g; + *b = orecolors[i].b; + *a = orecolors[i].a; + max_i = i; + break; + } + } + } +} + +static int +rendermode_mineral_start(void *data, RenderState *state) { + RenderModeMineral* self; + + /* first, chain up */ + int ret = rendermode_overlay.start(data, state); + if (ret != 0) + return ret; + + /* now do custom initializations */ + self = (RenderModeMineral *)data; + + /* setup custom color */ + self->parent.get_color = get_color; + + return 0; +} + +static void +rendermode_mineral_finish(void *data, RenderState *state) { + /* first free all *our* stuff */ + //RenderModeMineral* self = (RenderModeMineral *)data; + + /* now, chain up */ + rendermode_overlay.finish(data, state); +} + +static int +rendermode_mineral_occluded(void *data, RenderState *state) { + /* no special occlusion here */ + return rendermode_overlay.occluded(data, state); +} + +static void +rendermode_mineral_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { + /* draw normally */ + rendermode_overlay.draw(data, state, src, mask); +} + +RenderModeInterface rendermode_mineral = { + "mineral", "draws a colored overlay showing where ores are located", + &rendermode_overlay, + sizeof(RenderModeMineral), + rendermode_mineral_start, + rendermode_mineral_finish, + rendermode_mineral_occluded, + rendermode_mineral_draw, +}; diff --git a/src/rendermodes.c b/src/rendermodes.c index 43658e1..2d1f8d1 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -27,6 +27,7 @@ static RenderModeInterface *render_modes[] = { &rendermode_night, &rendermode_spawn, &rendermode_cave, + &rendermode_mineral, NULL }; diff --git a/src/rendermodes.h b/src/rendermodes.h index fd0b479..9e731b1 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -156,4 +156,11 @@ typedef struct { } RenderModeCave; extern RenderModeInterface rendermode_cave; +/* MINERAL */ +typedef struct { + /* inherits from overlay */ + RenderModeOverlay parent; +} RenderModeMineral; +extern RenderModeInterface rendermode_mineral; + #endif /* __RENDERMODES_H_INCLUDED__ */ From 4b7bc18926c77590e3c8bd70fb7e658465af20d1 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 2 May 2011 18:38:36 -0400 Subject: [PATCH 02/29] added more ores to mineral overlay --- src/rendermode-mineral.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c index a45bbf2..ab9cc95 100644 --- a/src/rendermode-mineral.c +++ b/src/rendermode-mineral.c @@ -24,7 +24,16 @@ struct OreColor { /* put more valuable ores first -- they take precedence */ static struct OreColor orecolors[] = { - {56 /* Diamond Ore */, 32, 230, 220, 200}, + {56 /* Diamond Ore */, 32, 230, 220, 200}, + + {14 /* Gold Ore */, 255, 234, 0, 200}, + {21 /* Lapis Lazuli */, 0, 23, 176, 200}, + + {15 /* Iron Ore */, 204, 204, 204, 200}, + {16 /* Coal Ore */, 54, 54, 54, 200}, + + {73 /* Redstone */, 186, 0, 0, 200}, + {74 /* Lit Redstone */, 186, 0, 0, 200}, /* end of list marker */ {0, 0, 0, 0, 0} From 1d858cd9e213fc1432eb7e762c10c1075d49343c Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 2 May 2011 18:50:07 -0400 Subject: [PATCH 03/29] added alpha fading based on height --- src/rendermode-mineral.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c index ab9cc95..00aef49 100644 --- a/src/rendermode-mineral.c +++ b/src/rendermode-mineral.c @@ -19,24 +19,24 @@ struct OreColor { unsigned char blockid; - unsigned char r, g, b, a; + unsigned char r, g, b; }; /* put more valuable ores first -- they take precedence */ static struct OreColor orecolors[] = { - {56 /* Diamond Ore */, 32, 230, 220, 200}, + {56 /* Diamond Ore */, 32, 230, 220}, - {14 /* Gold Ore */, 255, 234, 0, 200}, - {21 /* Lapis Lazuli */, 0, 23, 176, 200}, + {14 /* Gold Ore */, 255, 234, 0}, + {21 /* Lapis Lazuli */, 0, 23, 176}, - {15 /* Iron Ore */, 204, 204, 204, 200}, - {16 /* Coal Ore */, 54, 54, 54, 200}, + {15 /* Iron Ore */, 204, 204, 204}, + {16 /* Coal Ore */, 54, 54, 54}, - {73 /* Redstone */, 186, 0, 0, 200}, - {74 /* Lit Redstone */, 186, 0, 0, 200}, + {73 /* Redstone */, 186, 0, 0}, + {74 /* Lit Redstone */, 186, 0, 0}, /* end of list marker */ - {0, 0, 0, 0, 0} + {0, 0, 0, 0} }; static void get_color(void *data, RenderState *state, @@ -47,7 +47,7 @@ static void get_color(void *data, RenderState *state, *a = 0; for (z = 0; z <= z_max; z++) { - int i, max_i = sizeof(orecolors) / sizeof(struct OreColor); + int i, tmp, max_i = sizeof(orecolors) / sizeof(struct OreColor); unsigned char blockid = getArrayByte3D(state->blocks, x, y, z); for (i = 0; i < max_i && orecolors[i].blockid != 0; i++) { @@ -55,7 +55,10 @@ static void get_color(void *data, RenderState *state, *r = orecolors[i].r; *g = orecolors[i].g; *b = orecolors[i].b; - *a = orecolors[i].a; + + tmp = (128 - z_max + z) * 2 - 40; + *a = MIN(MAX(0, tmp), 255); + max_i = i; break; } From b1bb1975b58df6553b34f6b2d884b7cead57ee16 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 4 May 2011 14:08:59 -0400 Subject: [PATCH 04/29] added mossy cobble to mineral overlay, reordered priorities --- src/rendermode-mineral.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c index 00aef49..ea9b313 100644 --- a/src/rendermode-mineral.c +++ b/src/rendermode-mineral.c @@ -24,16 +24,17 @@ struct OreColor { /* put more valuable ores first -- they take precedence */ static struct OreColor orecolors[] = { + {48 /* Mossy Stone */, 31, 153, 9}, + {56 /* Diamond Ore */, 32, 230, 220}, - {14 /* Gold Ore */, 255, 234, 0}, {21 /* Lapis Lazuli */, 0, 23, 176}, + {14 /* Gold Ore */, 255, 234, 0}, {15 /* Iron Ore */, 204, 204, 204}, - {16 /* Coal Ore */, 54, 54, 54}, - {73 /* Redstone */, 186, 0, 0}, {74 /* Lit Redstone */, 186, 0, 0}, + {16 /* Coal Ore */, 54, 54, 54}, /* end of list marker */ {0, 0, 0, 0} From b654f3169fec3d2a3520354bfc04e432f7821834 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 9 Jun 2011 21:00:24 -0400 Subject: [PATCH 05/29] cleaned up rendermode interface --- src/iterate.c | 20 +++++++++---------- src/rendermodes.c | 49 ++++++++++++++++++++++++++++++++++++++--------- src/rendermodes.h | 17 ++++++++++++---- 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/iterate.c b/src/iterate.c index d86ecbf..92b176b 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -292,6 +292,7 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { PyObject* chunk_render(PyObject *self, PyObject *args) { RenderState state; + PyObject *rendermode_py; int xoff, yoff; @@ -304,10 +305,8 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *up_left_blocks_py; PyObject *up_right_blocks_py; - RenderModeInterface *rendermode; + RenderMode *rendermode; - void *rm_data; - PyObject *t = NULL; if (!PyArg_ParseTuple(args, "OOiiO", &state.self, &state.img, &xoff, &yoff, &state.blockdata_expanded)) @@ -318,10 +317,10 @@ chunk_render(PyObject *self, PyObject *args) { state.chunk = chunk_mod; /* set up the render mode */ - rendermode = get_render_mode(&state); - rm_data = calloc(1, rendermode->data_size); - if (rendermode->start(rm_data, &state)) { - free(rm_data); + rendermode_py = PyObject_GetAttrString(state.self, "rendermode"); + rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); + Py_DECREF(rendermode_py); + if (rendermode == NULL) { return Py_BuildValue("i", "-1"); } @@ -388,7 +387,7 @@ chunk_render(PyObject *self, PyObject *args) { blockid = PyInt_FromLong(state.block); // check for occlusion - if (rendermode->occluded(rm_data, &state)) { + if (render_mode_occluded(rendermode)) { continue; } @@ -428,7 +427,7 @@ chunk_render(PyObject *self, PyObject *args) { if (mask == Py_None) mask = src; - rendermode->draw(rm_data, &state, src, mask, mask_light); + render_mode_draw(rendermode, src, mask, mask_light); } } @@ -440,8 +439,7 @@ chunk_render(PyObject *self, PyObject *args) { } /* free up the rendermode info */ - rendermode->finish(rm_data, &state); - free(rm_data); + render_mode_destroy(rendermode); Py_DECREF(blocks_py); Py_XDECREF(left_blocks_py); diff --git a/src/rendermodes.c b/src/rendermodes.c index 43658e1..4eac913 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -30,23 +30,54 @@ static RenderModeInterface *render_modes[] = { NULL }; -/* decides which render mode to use */ -RenderModeInterface *get_render_mode(RenderState *state) { +RenderMode *render_mode_create(const char *mode, RenderState *state) { unsigned int i; - /* default: NULL --> an error */ + RenderMode *ret = NULL; RenderModeInterface *iface = NULL; - PyObject *rendermode_py = PyObject_GetAttrString(state->self, "rendermode"); - const char *rendermode = PyString_AsString(rendermode_py); - for (i = 0; render_modes[i] != NULL; i++) { - if (strcmp(render_modes[i]->name, rendermode) == 0) { + if (strcmp(render_modes[i]->name, mode) == 0) { iface = render_modes[i]; break; } } - Py_DECREF(rendermode_py); - return iface; + if (iface == NULL) + return NULL; + + ret = malloc(sizeof(RenderMode)); + if (ret == NULL) + return NULL; + + ret->mode = malloc(iface->data_size); + if (ret->mode == NULL) { + free(ret); + return NULL; + } + + ret->iface = iface; + ret->state = state; + + if (iface->start(ret->mode, state)) { + free(ret->mode); + free(ret); + return NULL; + } + + return ret; +} + +void render_mode_destroy(RenderMode *self) { + self->iface->finish(self->mode, self->state); + free(self->mode); + free(self); +} + +int render_mode_occluded(RenderMode *self) { + return self->iface->occluded(self->mode, self->state); +} + +void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light) { + self->iface->draw(self->mode, self->state, img, mask, mask_light); } /* bindings for python -- get all the rendermode names */ diff --git a/src/rendermodes.h b/src/rendermodes.h index 80126a4..5be98eb 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -59,8 +59,19 @@ struct _RenderModeInterface { void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *); }; -/* figures out the render mode to use from the given ChunkRenderer */ -RenderModeInterface *get_render_mode(RenderState *state); +/* wrapper for passing around rendermodes */ +typedef struct { + void *mode; + RenderModeInterface *iface; + RenderState *state; +} RenderMode; + +/* functions for creating / using rendermodes */ +RenderMode *render_mode_create(const char *mode, RenderState *state); +void render_mode_destroy(RenderMode *self); +int render_mode_occluded(RenderMode *self); +void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light); + /* python bindings */ PyObject *get_render_modes(PyObject *self, PyObject *args); PyObject *get_render_mode_info(PyObject *self, PyObject *args); @@ -117,8 +128,6 @@ typedef struct { float (*calculate_darkness)(unsigned char, unsigned char); } RenderModeLighting; extern RenderModeInterface rendermode_lighting; -inline float get_lighting_coefficient(RenderModeLighting *self, RenderState *state, - int x, int y, int z, int *authoratative); /* NIGHT */ typedef struct { From 6d667cb262f66dc1c56e73d2fd5e31098d777d2a Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 9 Jun 2011 23:23:48 -0400 Subject: [PATCH 06/29] added (currently unchecked) global rendermode option support --- overviewer.py | 3 +- rendernode.py | 4 +++ src/main.c | 3 ++ src/rendermode-cave.c | 4 +-- src/rendermode-lighting.c | 4 +-- src/rendermode-night.c | 4 +-- src/rendermode-normal.c | 2 +- src/rendermode-overlay.c | 2 +- src/rendermode-spawn.c | 4 +-- src/rendermodes.c | 64 +++++++++++++++++++++++++++++++++++++-- src/rendermodes.h | 9 ++++-- 11 files changed, 86 insertions(+), 17 deletions(-) diff --git a/overviewer.py b/overviewer.py index 1bf6790..565e279 100755 --- a/overviewer.py +++ b/overviewer.py @@ -97,6 +97,7 @@ def main(): parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting the entire map with --delete.", action="store_true") parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, required=True, default=avail_rendermodes[0], listify=True) parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", help="List available render modes and exit.", commandLineOnly=True) + parser.add_option("--rendermode-options", dest="rendermode_options", default={}, configFileOnly=True) parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", configFileOnly=True ) parser.add_option("--imgquality", dest="imgquality", default=95, help="Specify the quality of image output when using imgformat=\"jpg\".", type="int", configFileOnly=True) parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A") @@ -217,7 +218,7 @@ def main(): logging.info("Welcome to Minecraft Overviewer!") logging.debug("Current log level: {0}".format(logging.getLogger().level)) - + useBiomeData = os.path.exists(os.path.join(worlddir, 'biomes')) if not useBiomeData: logging.info("Notice: Not using biome data for tinting") diff --git a/rendernode.py b/rendernode.py index 6f6c76e..f2b9bfb 100644 --- a/rendernode.py +++ b/rendernode.py @@ -68,6 +68,10 @@ def pool_initializer(rendernode): textures.generate(path=rendernode.options.get('textures_path', None)) c_overviewer.init_chunk_render() + # setup c_overviewer rendermode options + for mode in rendernode.options.rendermode_options: + c_overviewer.set_render_mode_options(mode, rendernode.options.rendermode_options[mode]) + # load biome data in each process, if needed for quadtree in rendernode.quadtrees: if quadtree.world.useBiomeData: diff --git a/src/main.c b/src/main.c index 19d3612..a001be1 100644 --- a/src/main.c +++ b/src/main.c @@ -42,6 +42,9 @@ static PyMethodDef COverviewerMethods[] = { {"get_render_mode_children", get_render_mode_children, METH_VARARGS, "returns (direct) children for a particular render mode"}, + {"set_render_mode_options", set_render_mode_options, METH_VARARGS, + "sets the default options for a given render mode"}, + {"extension_version", get_extension_version, METH_VARARGS, "Returns the extension version"}, diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index c5a2e07..88ee1e7 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -161,13 +161,13 @@ rendermode_cave_occluded(void *data, RenderState *state) { } static int -rendermode_cave_start(void *data, RenderState *state) { +rendermode_cave_start(void *data, RenderState *state, PyObject *options) { RenderModeCave* self; int ret; self = (RenderModeCave *)data; /* first, chain up */ - ret = rendermode_normal.start(data, state); + ret = rendermode_normal.start(data, state, options); if (ret != 0) return ret; diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index d0d4c64..f1dc6c7 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -169,11 +169,11 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state, } static int -rendermode_lighting_start(void *data, RenderState *state) { +rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { RenderModeLighting* self; /* first, chain up */ - int ret = rendermode_normal.start(data, state); + int ret = rendermode_normal.start(data, state, options); if (ret != 0) return ret; diff --git a/src/rendermode-night.c b/src/rendermode-night.c index 81fc38f..35c4476 100644 --- a/src/rendermode-night.c +++ b/src/rendermode-night.c @@ -26,11 +26,11 @@ static float calculate_darkness(unsigned char skylight, unsigned char blocklight } static int -rendermode_night_start(void *data, RenderState *state) { +rendermode_night_start(void *data, RenderState *state, PyObject *options) { RenderModeNight* self; /* first, chain up */ - int ret = rendermode_lighting.start(data, state); + int ret = rendermode_lighting.start(data, state, options); if (ret != 0) return ret; diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index b112192..f5fb124 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -18,7 +18,7 @@ #include "overviewer.h" static int -rendermode_normal_start(void *data, RenderState *state) { +rendermode_normal_start(void *data, RenderState *state, PyObject *options) { PyObject *chunk_x_py, *chunk_y_py, *world, *use_biomes, *worlddir; RenderModeNormal *self = (RenderModeNormal *)data; diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 04c87bf..7807f66 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -26,7 +26,7 @@ static void get_color(void *data, RenderState *state, } static int -rendermode_overlay_start(void *data, RenderState *state) { +rendermode_overlay_start(void *data, RenderState *state, PyObject *options) { PyObject *facemasks_py; RenderModeOverlay *self = (RenderModeOverlay *)data; diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index 2781a2a..20f81dd 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -62,11 +62,11 @@ static void get_color(void *data, RenderState *state, } static int -rendermode_spawn_start(void *data, RenderState *state) { +rendermode_spawn_start(void *data, RenderState *state, PyObject *options) { RenderModeSpawn* self; /* first, chain up */ - int ret = rendermode_overlay.start(data, state); + int ret = rendermode_overlay.start(data, state, options); if (ret != 0) return ret; diff --git a/src/rendermodes.c b/src/rendermodes.c index 4eac913..8c11c83 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -30,8 +30,41 @@ static RenderModeInterface *render_modes[] = { NULL }; +static PyObject *render_mode_options = NULL; + +/* rendermode encapsulation */ + +/* helper to recursively find options for a given mode */ +static inline PyObject * +render_mode_create_options(RenderModeInterface *iface) { + PyObject *base_options, *ret, *parent_options; + if (render_mode_options == NULL) + return PyDict_New(); + + base_options = PyDict_GetItemString(render_mode_options, iface->name); + if (base_options) { + ret = PyDict_Copy(base_options); + } else { + ret = PyDict_New(); + } + + if (iface->parent) { + parent_options = render_mode_create_options(iface->parent); + if (parent_options) { + if (PyDict_Merge(ret, parent_options, 0) == -1) { + Py_DECREF(parent_options); + return NULL; + } + Py_DECREF(parent_options); + } + } + + return ret; +} + RenderMode *render_mode_create(const char *mode, RenderState *state) { unsigned int i; + PyObject *options; RenderMode *ret = NULL; RenderModeInterface *iface = NULL; for (i = 0; render_modes[i] != NULL; i++) { @@ -44,12 +77,19 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) { if (iface == NULL) return NULL; - ret = malloc(sizeof(RenderMode)); - if (ret == NULL) + options = render_mode_create_options(iface); + if (options == NULL) return NULL; + ret = malloc(sizeof(RenderMode)); + if (ret == NULL) { + Py_DECREF(options); + return NULL; + } + ret->mode = malloc(iface->data_size); if (ret->mode == NULL) { + Py_DECREF(options); free(ret); return NULL; } @@ -57,12 +97,14 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) { ret->iface = iface; ret->state = state; - if (iface->start(ret->mode, state)) { + if (iface->start(ret->mode, state, options)) { + Py_DECREF(options); free(ret->mode); free(ret); return NULL; } + Py_DECREF(options); return ret; } @@ -213,3 +255,19 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { return children; } + +/* python rendermode options bindings */ +PyObject *set_render_mode_options(PyObject *self, PyObject *args) { + const char *rendermode; + PyObject *opts; + if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts)) + return NULL; + + /* check options here */ + + if (render_mode_options == NULL) + render_mode_options = PyDict_New(); + + PyDict_SetItemString(render_mode_options, rendermode, opts); + Py_RETURN_NONE; +} diff --git a/src/rendermodes.h b/src/rendermodes.h index 5be98eb..a369d77 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -50,8 +50,8 @@ struct _RenderModeInterface { /* the size of the local storage for this rendermode */ unsigned int data_size; - /* may return non-zero on error */ - int (*start)(void *, RenderState *); + /* may return non-zero on error, last arg is options */ + int (*start)(void *, RenderState *, PyObject *); void (*finish)(void *, RenderState *); /* returns non-zero to skip rendering this block */ int (*occluded)(void *, RenderState *); @@ -72,13 +72,16 @@ void render_mode_destroy(RenderMode *self); int render_mode_occluded(RenderMode *self); void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light); -/* python bindings */ +/* python metadata bindings */ PyObject *get_render_modes(PyObject *self, PyObject *args); PyObject *get_render_mode_info(PyObject *self, PyObject *args); PyObject *get_render_mode_parent(PyObject *self, PyObject *args); PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args); PyObject *get_render_mode_children(PyObject *self, PyObject *args); +/* python rendermode options bindings */ +PyObject *set_render_mode_options(PyObject *self, PyObject *args); + /* individual rendermode interface declarations follow */ /* NORMAL */ From a37d0ce9bc508e0b27c341dcd2128d80651f78ce Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 10 Jun 2011 22:27:46 -0400 Subject: [PATCH 07/29] added options metadata (and python accessor) --- src/main.c | 2 ++ src/rendermode-cave.c | 1 + src/rendermode-lighting.c | 1 + src/rendermode-night.c | 1 + src/rendermode-normal.c | 7 ++++++ src/rendermode-overlay.c | 1 + src/rendermode-spawn.c | 1 + src/rendermodes.c | 45 +++++++++++++++++++++++++++++++++++++++ src/rendermodes.h | 13 +++++++++-- 9 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index a001be1..6345d8c 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,8 @@ static PyMethodDef COverviewerMethods[] = { "returns inheritance chain for a particular render mode"}, {"get_render_mode_children", get_render_mode_children, METH_VARARGS, "returns (direct) children for a particular render mode"}, + {"get_render_mode_options", get_render_mode_options, METH_VARARGS, + "returns a list of options for this render mode"}, {"set_render_mode_options", set_render_mode_options, METH_VARARGS, "sets the default options for a given render mode"}, diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index 88ee1e7..e4275e5 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -225,6 +225,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma RenderModeInterface rendermode_cave = { "cave", "render only caves in normal mode", + NULL, &rendermode_normal, sizeof(RenderModeCave), rendermode_cave_start, diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index f1dc6c7..f3e529b 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -246,6 +246,7 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject RenderModeInterface rendermode_lighting = { "lighting", "draw shadows from the lighting data", + NULL, &rendermode_normal, sizeof(RenderModeLighting), rendermode_lighting_start, diff --git a/src/rendermode-night.c b/src/rendermode-night.c index 35c4476..f3edc68 100644 --- a/src/rendermode-night.c +++ b/src/rendermode-night.c @@ -61,6 +61,7 @@ rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *m RenderModeInterface rendermode_night = { "night", "like \"lighting\", except at night", + NULL, &rendermode_lighting, sizeof(RenderModeNight), rendermode_night_start, diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index f5fb124..fb7eb0e 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -244,8 +244,15 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * } } +static RenderModeOption rendermode_normal_options[] = { + {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0"}, + {"min_depth", "lowest level of blocks to render, default: 0"}, + {"max_depth", "highest level of blocks to render, default: 127"}, +}; + RenderModeInterface rendermode_normal = { "normal", "nothing special, just render the blocks", + rendermode_normal_options, NULL, sizeof(RenderModeNormal), rendermode_normal_start, diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 7807f66..342a6f9 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -129,6 +129,7 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject RenderModeInterface rendermode_overlay = { "overlay", "base rendermode for informational overlays", NULL, + NULL, sizeof(RenderModeOverlay), rendermode_overlay_start, rendermode_overlay_finish, diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index 20f81dd..4fff748 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -109,6 +109,7 @@ rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *m RenderModeInterface rendermode_spawn = { "spawn", "draws a red overlay where monsters can spawn at night", + NULL, &rendermode_overlay, sizeof(RenderModeSpawn), rendermode_spawn_start, diff --git a/src/rendermodes.c b/src/rendermodes.c index 8c11c83..9cac54c 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -256,6 +256,51 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { return children; } +/* bindings -- get list of options */ +PyObject *get_render_mode_options(PyObject *self, PyObject *args) +{ + const char *rendermode; + PyObject *options; + unsigned int i, j; + if (!PyArg_ParseTuple(args, "s", &rendermode)) + return NULL; + + options = PyList_New(0); + if (!options) + return NULL; + + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, rendermode) == 0) { + if (render_modes[i]->options == NULL) + break; + + for (j = 0; render_modes[i]->options[j].name != NULL; j++) { + RenderModeOption opt = render_modes[i]->options[j]; + PyObject *name = PyString_FromString(opt.name); + PyObject *description = PyString_FromString(opt.description); + PyObject *option = PyDict_New(); + if (!name || !description || !option) { + Py_XDECREF(name); + Py_XDECREF(description); + Py_XDECREF(option); + Py_DECREF(options); + return NULL; + } + + PyDict_SetItemString(option, "name", name); + PyDict_SetItemString(option, "description", description); + PyList_Append(options, option); + Py_DECREF(name); + Py_DECREF(description); + Py_DECREF(option); + } + break; + } + } + + return options; +} + /* python rendermode options bindings */ PyObject *set_render_mode_options(PyObject *self, PyObject *args) { const char *rendermode; diff --git a/src/rendermodes.h b/src/rendermodes.h index a369d77..9aec63f 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -37,13 +37,21 @@ #include +typedef struct { + const char *name; + const char *description; +} RenderModeOption; + /* rendermode interface */ typedef struct _RenderModeInterface RenderModeInterface; struct _RenderModeInterface { /* the name of this mode */ - const char* name; + const char *name; /* the short description of this render mode */ - const char* description; + const char *description; + + /* a NULL-terminated list of render mode options, or NULL */ + RenderModeOption *options; /* the rendermode this is derived from, or NULL */ RenderModeInterface *parent; @@ -78,6 +86,7 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args); PyObject *get_render_mode_parent(PyObject *self, PyObject *args); PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args); PyObject *get_render_mode_children(PyObject *self, PyObject *args); +PyObject *get_render_mode_options(PyObject *self, PyObject *args); /* python rendermode options bindings */ PyObject *set_render_mode_options(PyObject *self, PyObject *args); From da706287c8d7caac43c7ae181c52cd99b59ca1ec Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 10 Jun 2011 23:15:24 -0400 Subject: [PATCH 08/29] added a couple of simple options to the 'normal' rendermode --- src/rendermode-normal.c | 52 ++++++++++++++++++++++++++++++++++++----- src/rendermodes.h | 4 ++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index fb7eb0e..a24bc80 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -19,9 +19,44 @@ static int rendermode_normal_start(void *data, RenderState *state, PyObject *options) { - PyObject *chunk_x_py, *chunk_y_py, *world, *use_biomes, *worlddir; + PyObject *opt, *chunk_x_py, *chunk_y_py, *world, *use_biomes, *worlddir; RenderModeNormal *self = (RenderModeNormal *)data; + /* load up the given options, first */ + + opt = PyDict_GetItemString(options, "edge_opacity"); + if (opt) { + if (!PyNumber_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'edge_opacity' must be a number"); + return 1; + } + self->edge_opacity = PyFloat_AsDouble(opt); + } else { + self->edge_opacity = 0.15; + } + + opt = PyDict_GetItemString(options, "min_depth"); + if (opt) { + if (!PyInt_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'min_depth' must be an integer"); + return 1; + } + self->min_depth = PyInt_AsLong(opt); + } else { + self->min_depth = 0; + } + + opt = PyDict_GetItemString(options, "max_depth"); + if (opt) { + if (!PyInt_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'max_depth' must be an integer"); + return 1; + } + self->max_depth = PyInt_AsLong(opt); + } else { + self->max_depth = 127; + } + chunk_x_py = PyObject_GetAttrString(state->self, "chunkX"); chunk_y_py = PyObject_GetAttrString(state->self, "chunkY"); @@ -110,9 +145,14 @@ rendermode_normal_finish(void *data, RenderState *state) { static int rendermode_normal_occluded(void *data, RenderState *state) { + RenderModeNormal *self = (RenderModeNormal *)data; int x = state->x, y = state->y, z = state->z; - if ( (x != 0) && (y != 15) && (z != 127) && + if (z > self->max_depth || z < self->min_depth) { + return 1; + } + + if ( (x != 0) && (y != 15) && (z != self->max_depth) && !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { @@ -203,7 +243,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) { Imaging img_i = imaging_python_to_c(state->img); - unsigned char ink[] = {0,0,0,40}; + unsigned char ink[] = {0, 0, 0, 255 * self->edge_opacity}; int increment=0; if (state->block == 44) // half-step @@ -245,9 +285,9 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * } static RenderModeOption rendermode_normal_options[] = { - {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0"}, - {"min_depth", "lowest level of blocks to render, default: 0"}, - {"max_depth", "highest level of blocks to render, default: 127"}, + {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)"}, + {"min_depth", "lowest level of blocks to render (default: 0)"}, + {"max_depth", "highest level of blocks to render (default: 127)"}, }; RenderModeInterface rendermode_normal = { diff --git a/src/rendermodes.h b/src/rendermodes.h index 9aec63f..a82dddb 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -105,6 +105,10 @@ typedef struct { PyObject *grass_texture, *leaf_texture, *tall_grass_texture, *tall_fern_texture; /* top facemask for grass biome tinting */ PyObject *facemask_top; + + float edge_opacity; + unsigned int min_depth; + unsigned int max_depth; } RenderModeNormal; extern RenderModeInterface rendermode_normal; From bfb92de7b779debf4420f39b16dd2e9532e99a40 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 11 Jun 2011 00:01:12 -0400 Subject: [PATCH 09/29] provided options are now checked against the available options --- rendernode.py | 2 ++ src/iterate.c | 7 +++---- src/rendermodes.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/rendernode.py b/rendernode.py index f2b9bfb..0d1836d 100644 --- a/rendernode.py +++ b/rendernode.py @@ -148,7 +148,9 @@ class RenderNode(object): pool = FakePool() pool_initializer(self) else: + pool_initializer(self) pool = multiprocessing.Pool(processes=procs,initializer=pool_initializer,initargs=(self,)) + #warm up the pool so it reports all the worker id's if logging.getLogger().level >= 10: pool.map(bool,xrange(multiprocessing.cpu_count()),1) diff --git a/src/iterate.c b/src/iterate.c index 92b176b..5d82aaa 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -26,11 +26,10 @@ static PyObject *transparent_blocks = NULL; PyObject *init_chunk_render(PyObject *self, PyObject *args) { - /* this function only needs to be called once, anything more is an - * error... */ + /* this function only needs to be called once, anything more should be + * ignored */ if (blockmap) { - PyErr_SetString(PyExc_RuntimeError, "init_chunk_render should only be called once per process."); - return NULL; + Py_RETURN_NONE; } textures = PyImport_ImportModule("textures"); diff --git a/src/rendermodes.c b/src/rendermodes.c index 9cac54c..cc19561 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -301,14 +301,56 @@ PyObject *get_render_mode_options(PyObject *self, PyObject *args) return options; } +/* helper to decide if a rendermode supports a given option */ +static inline int +render_mode_supports_option(RenderModeInterface *iface, const char *name) { + unsigned int i; + + if (iface->options != NULL) { + for (i = 0; iface->options[i].name != NULL; i++) { + if (strcmp(iface->options[i].name, name) == 0) { + return 1; + } + } + } + + if (iface->parent != NULL) + return render_mode_supports_option(iface->parent, name); + + return 0; +} + /* python rendermode options bindings */ PyObject *set_render_mode_options(PyObject *self, PyObject *args) { const char *rendermode; - PyObject *opts; + PyObject *opts, *key, *value; + Py_ssize_t pos = 0; + RenderModeInterface *iface = NULL; + unsigned int i; if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts)) return NULL; - /* check options here */ + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, rendermode) == 0) { + iface = render_modes[i]; + break; + } + } + + if (iface == NULL) { + return PyErr_Format(PyExc_ValueError, "'%s' is not a valid rendermode name", rendermode); + } + + /* check options to make sure they're available */ + while (PyDict_Next(opts, &pos, &key, &value)) { + const char *name = PyString_AsString(key); + if (name == NULL) + return NULL; + + if (!render_mode_supports_option(iface, name)) { + return PyErr_Format(PyExc_ValueError, "'%s' is not a valid option for rendermode '%s'", name, rendermode); + } + } if (render_mode_options == NULL) render_mode_options = PyDict_New(); From bd9b1873e3cf8f802ce68f8aa0cdb4ba51c3e577 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 11 Jun 2011 04:01:40 -0400 Subject: [PATCH 10/29] added support for "custom" rendermodes created in python --- configParser.py | 2 +- overviewer.py | 9 +- rendernode.py | 4 +- src/main.c | 6 +- src/rendermodes.c | 304 ++++++++++++++++++++++++++++++++++------------ src/rendermodes.h | 3 +- 6 files changed, 239 insertions(+), 89 deletions(-) diff --git a/configParser.py b/configParser.py index 01e6a14..4213984 100644 --- a/configParser.py +++ b/configParser.py @@ -166,7 +166,7 @@ class ConfigOptionParser(object): elif a['type'] == "long": return long(value) elif a['type'] == "choice": - if value not in a['choices']: + if ('choices' in a) and (value not in a['choices']): logging.error("The value '%s' is not valid for config parameter '%s'" % (value, a['dest'])) sys.exit(1) return value diff --git a/overviewer.py b/overviewer.py index 565e279..cea9bbb 100755 --- a/overviewer.py +++ b/overviewer.py @@ -95,9 +95,10 @@ def main(): parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true", commandLineOnly=True) parser.add_option("--regionlist", dest="regionlist", help="A file containing, on each line, a path to a regionlist to update. Instead of scanning the world directory for regions, it will just use this list. Normal caching rules still apply.") parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting the entire map with --delete.", action="store_true") - parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, required=True, default=avail_rendermodes[0], listify=True) + parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", required=True, default=avail_rendermodes[0], listify=True) parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", help="List available render modes and exit.", commandLineOnly=True) parser.add_option("--rendermode-options", dest="rendermode_options", default={}, configFileOnly=True) + parser.add_option("--custom-rendermodes", dest="custom_rendermodes", default={}, configFileOnly=True) parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", configFileOnly=True ) parser.add_option("--imgquality", dest="imgquality", default=95, help="Specify the quality of image output when using imgformat=\"jpg\".", type="int", configFileOnly=True) parser.add_option("--bg_color", dest="bg_color", help="Configures the background color for the GoogleMap output. Specify in #RRGGBB format", configFileOnly=True, type="string", default="#1A1A1A") @@ -126,6 +127,12 @@ def main(): except: pass sys.exit(0) + + # setup c_overviewer rendermode customs / options + for mode in options.custom_rendermodes: + c_overviewer.add_custom_render_mode(mode, options.custom_rendermodes[mode]) + for mode in options.rendermode_options: + c_overviewer.set_render_mode_options(mode, options.rendermode_options[mode]) if options.list_rendermodes: rendermode_info = map(c_overviewer.get_render_mode_info, avail_rendermodes) diff --git a/rendernode.py b/rendernode.py index 0d1836d..e2d1dff 100644 --- a/rendernode.py +++ b/rendernode.py @@ -68,7 +68,9 @@ def pool_initializer(rendernode): textures.generate(path=rendernode.options.get('textures_path', None)) c_overviewer.init_chunk_render() - # setup c_overviewer rendermode options + # setup c_overviewer rendermode customs / options + for mode in rendernode.options.custom_rendermodes: + c_overviewer.add_custom_render_mode(mode, rendernode.options.custom_rendermodes[mode]) for mode in rendernode.options.rendermode_options: c_overviewer.set_render_mode_options(mode, rendernode.options.rendermode_options[mode]) diff --git a/src/main.c b/src/main.c index 6345d8c..0adb883 100644 --- a/src/main.c +++ b/src/main.c @@ -35,17 +35,15 @@ static PyMethodDef COverviewerMethods[] = { "returns available render modes"}, {"get_render_mode_info", get_render_mode_info, METH_VARARGS, "returns info for a particular render mode"}, - {"get_render_mode_parent", get_render_mode_parent, METH_VARARGS, - "returns parent for a particular render mode"}, {"get_render_mode_inheritance", get_render_mode_inheritance, METH_VARARGS, "returns inheritance chain for a particular render mode"}, {"get_render_mode_children", get_render_mode_children, METH_VARARGS, "returns (direct) children for a particular render mode"}, - {"get_render_mode_options", get_render_mode_options, METH_VARARGS, - "returns a list of options for this render mode"}, {"set_render_mode_options", set_render_mode_options, METH_VARARGS, "sets the default options for a given render mode"}, + {"add_custom_render_mode", add_custom_render_mode, METH_VARARGS, + "add a new rendermode derived from an existing mode"}, {"extension_version", get_extension_version, METH_VARARGS, "Returns the extension version"}, diff --git a/src/rendermodes.c b/src/rendermodes.c index cc19561..eb88517 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -31,25 +31,52 @@ static RenderModeInterface *render_modes[] = { }; static PyObject *render_mode_options = NULL; +static PyObject *custom_render_modes = NULL; /* rendermode encapsulation */ /* helper to recursively find options for a given mode */ static inline PyObject * -render_mode_create_options(RenderModeInterface *iface) { +render_mode_create_options(const char *mode) { + const char *parent = NULL; PyObject *base_options, *ret, *parent_options; + unsigned int i, found_concrete; if (render_mode_options == NULL) return PyDict_New(); - base_options = PyDict_GetItemString(render_mode_options, iface->name); + base_options = PyDict_GetItemString(render_mode_options, mode); if (base_options) { ret = PyDict_Copy(base_options); } else { ret = PyDict_New(); } - if (iface->parent) { - parent_options = render_mode_create_options(iface->parent); + /* figure out the parent mode name */ + found_concrete = 0; + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, mode) == 0) { + found_concrete = 1; + if (render_modes[i]->parent) { + parent = render_modes[i]->parent->name; + } + break; + } + } + + /* check custom mode info if needed */ + if (found_concrete == 1 && custom_render_modes != NULL) { + PyObject *custom = PyDict_GetItemString(custom_render_modes, mode); + if (custom) { + custom = PyDict_GetItemString(custom, "parent"); + if (custom) { + parent = PyString_AsString(custom); + } + } + } + + /* merge parent options, if the parent was found */ + if (parent) { + parent_options = render_mode_create_options(parent); if (parent_options) { if (PyDict_Merge(ret, parent_options, 0) == -1) { Py_DECREF(parent_options); @@ -62,22 +89,45 @@ render_mode_create_options(RenderModeInterface *iface) { return ret; } -RenderMode *render_mode_create(const char *mode, RenderState *state) { +/* helper to find the first concrete, C interface for a given mode */ +inline static RenderModeInterface * +render_mode_find_interface(const char *mode) { + PyObject *custom; + const char *custom_parent; unsigned int i; + + /* if it is *itself* concrete, we're done */ + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, mode) == 0) + return render_modes[i]; + } + + /* check for custom modes */ + if (custom_render_modes == NULL) + return NULL; + custom = PyDict_GetItemString(custom_render_modes, mode); + if (custom == NULL) + return NULL; + custom = PyDict_GetItemString(custom, "parent"); + if (custom == NULL) + return NULL; + custom_parent = PyString_AsString(custom); + if (custom_parent == NULL) + return NULL; + + return render_mode_find_interface(custom_parent); +} + +RenderMode *render_mode_create(const char *mode, RenderState *state) { PyObject *options; RenderMode *ret = NULL; RenderModeInterface *iface = NULL; - for (i = 0; render_modes[i] != NULL; i++) { - if (strcmp(render_modes[i]->name, mode) == 0) { - iface = render_modes[i]; - break; - } - } + iface = render_mode_find_interface(mode); if (iface == NULL) return NULL; - options = render_mode_create_options(iface); + options = render_mode_create_options(mode); if (options == NULL) return NULL; @@ -139,9 +189,61 @@ PyObject *get_render_modes(PyObject *self, PyObject *args) { Py_DECREF(name); } + if (custom_render_modes != NULL) { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { + PyList_Append(modes, key); + } + } + return modes; } +/* helper, get the list of options for a render mode */ +static inline PyObject * +get_render_mode_options(const char *rendermode) +{ + PyObject *options; + unsigned int i, j; + + options = PyList_New(0); + if (!options) + return NULL; + + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, rendermode) == 0) { + if (render_modes[i]->options == NULL) + break; + + for (j = 0; render_modes[i]->options[j].name != NULL; j++) { + RenderModeOption opt = render_modes[i]->options[j]; + PyObject *name = PyString_FromString(opt.name); + PyObject *description = PyString_FromString(opt.description); + PyObject *option = PyDict_New(); + if (!name || !description || !option) { + Py_XDECREF(name); + Py_XDECREF(description); + Py_XDECREF(option); + Py_DECREF(options); + return NULL; + } + + PyDict_SetItemString(option, "name", name); + PyDict_SetItemString(option, "description", description); + PyList_Append(options, option); + Py_DECREF(name); + Py_DECREF(description); + Py_DECREF(option); + } + break; + } + } + + return options; +} + /* more bindings -- return info for a given rendermode name */ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { const char* rendermode; @@ -166,33 +268,39 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { PyDict_SetItemString(info, "description", tmp); Py_DECREF(tmp); + tmp = get_render_mode_options(rendermode); + PyDict_SetItemString(info, "options", tmp); + Py_DECREF(tmp); + + if (render_modes[i]->parent != NULL) { + tmp = PyString_FromString(render_modes[i]->parent->name); + PyDict_SetItemString(info, "parent", tmp); + Py_DECREF(tmp); + } + return info; } } - Py_DECREF(info); - return PyErr_Format(PyExc_ValueError, "invalid rendermode: \"%s\"", rendermode); -} - -/* bindings -- get parent's name */ -PyObject *get_render_mode_parent(PyObject *self, PyObject *args) { - const char *rendermode; - unsigned int i; - if (!PyArg_ParseTuple(args, "s", &rendermode)) - return NULL; - - for (i = 0; render_modes[i] != NULL; i++) { - if (strcmp(render_modes[i]->name, rendermode) == 0) { - if (render_modes[i]->parent) { - /* has parent */ - return PyString_FromString(render_modes[i]->parent->name); - } else { - /* no parent */ - Py_RETURN_NONE; - } + if (custom_render_modes != NULL) { + PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + if (custom) { + PyObject *tmp, *copy = PyDict_Copy(custom); + Py_DECREF(info); + + tmp = PyString_FromString(rendermode); + PyDict_SetItemString(copy, "name", tmp); + Py_DECREF(tmp); + + tmp = PyList_New(0); + PyDict_SetItemString(copy, "options", tmp); + Py_DECREF(tmp); + + return copy; } } + Py_DECREF(info); return PyErr_Format(PyExc_ValueError, "invalid rendermode: \"%s\"", rendermode); } @@ -209,6 +317,21 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { if (!parents) return NULL; + /* take care of the chain of custom modes, if there are any */ + if (custom_render_modes != NULL) { + PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + while (custom != NULL) { + PyObject *name = PyString_FromString(rendermode); + PyList_Append(parents, name); + Py_DECREF(name); + + custom = PyDict_GetItemString(custom, "parent"); + rendermode = PyString_AsString(custom); + custom = PyDict_GetItem(custom_render_modes, custom); + } + } + + /* now handle concrete modes */ for (i = 0; render_modes[i] != NULL; i++) { if (strcmp(render_modes[i]->name, rendermode) == 0) { iface = render_modes[i]; @@ -253,52 +376,21 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { } } - return children; -} - -/* bindings -- get list of options */ -PyObject *get_render_mode_options(PyObject *self, PyObject *args) -{ - const char *rendermode; - PyObject *options; - unsigned int i, j; - if (!PyArg_ParseTuple(args, "s", &rendermode)) - return NULL; - - options = PyList_New(0); - if (!options) - return NULL; - - for (i = 0; render_modes[i] != NULL; i++) { - if (strcmp(render_modes[i]->name, rendermode) == 0) { - if (render_modes[i]->options == NULL) - break; + if (custom_render_modes != NULL) { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { + PyObject *pyparent = PyDict_GetItemString(value, "parent"); + const char *parent = PyString_AsString(pyparent); - for (j = 0; render_modes[i]->options[j].name != NULL; j++) { - RenderModeOption opt = render_modes[i]->options[j]; - PyObject *name = PyString_FromString(opt.name); - PyObject *description = PyString_FromString(opt.description); - PyObject *option = PyDict_New(); - if (!name || !description || !option) { - Py_XDECREF(name); - Py_XDECREF(description); - Py_XDECREF(option); - Py_DECREF(options); - return NULL; - } - - PyDict_SetItemString(option, "name", name); - PyDict_SetItemString(option, "description", description); - PyList_Append(options, option); - Py_DECREF(name); - Py_DECREF(description); - Py_DECREF(option); + if (strcmp(parent, rendermode) == 0) { + PyList_Append(children, key); } - break; } } - return options; + return children; } /* helper to decide if a rendermode supports a given option */ @@ -326,16 +418,10 @@ PyObject *set_render_mode_options(PyObject *self, PyObject *args) { PyObject *opts, *key, *value; Py_ssize_t pos = 0; RenderModeInterface *iface = NULL; - unsigned int i; if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts)) return NULL; - for (i = 0; render_modes[i] != NULL; i++) { - if (strcmp(render_modes[i]->name, rendermode) == 0) { - iface = render_modes[i]; - break; - } - } + iface = render_mode_find_interface(rendermode); if (iface == NULL) { return PyErr_Format(PyExc_ValueError, "'%s' is not a valid rendermode name", rendermode); @@ -358,3 +444,61 @@ PyObject *set_render_mode_options(PyObject *self, PyObject *args) { PyDict_SetItemString(render_mode_options, rendermode, opts); Py_RETURN_NONE; } + +PyObject *add_custom_render_mode(PyObject *self, PyObject *args) { + const char *rendermode, *parentmode; + PyObject *opts, *options, *pyparent; + if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts)) + return NULL; + + if (custom_render_modes == NULL) + custom_render_modes = PyDict_New(); + + /* first, make sure the parent is set correctly */ + pyparent = PyDict_GetItemString(opts, "parent"); + if (pyparent == NULL) + return PyErr_Format(PyExc_ValueError, "'%s' does not have a parent mode", rendermode); + parentmode = PyString_AsString(pyparent); + if (parentmode == NULL) + return PyErr_Format(PyExc_ValueError, "'%s' does not have a valid parent", rendermode); + + /* check that parentmode exists */ + if (PyDict_GetItemString(custom_render_modes, parentmode) == NULL) { + unsigned int parent_valid = 0, i; + for (i = 0; render_modes[i] != NULL; i++) { + if (strcmp(render_modes[i]->name, parentmode) == 0) { + parent_valid = 1; + } + } + + if (parent_valid == 0) + return PyErr_Format(PyExc_ValueError, "'%s' parent '%s' is not valid", rendermode, parentmode); + } + + /* remove and handle options seperately, if needed */ + options = PyDict_GetItemString(opts, "options"); + if (options != NULL) { + PyObject *opts_copy, *set_opts_args; + + opts_copy = PyDict_Copy(opts); + if (opts_copy == NULL) + return NULL; + + PyDict_DelItemString(opts_copy, "options"); + PyDict_SetItemString(custom_render_modes, rendermode, opts_copy); + Py_DECREF(opts_copy); + + /* call set_render_mode_options */ + set_opts_args = Py_BuildValue("sO", rendermode, options); + if (set_opts_args == NULL) + return NULL; + if (set_render_mode_options(NULL, set_opts_args) == NULL) { + Py_DECREF(set_opts_args); + return NULL; + } + Py_DECREF(set_opts_args); + } else { + PyDict_SetItemString(custom_render_modes, rendermode, opts); + } + Py_RETURN_NONE; +} diff --git a/src/rendermodes.h b/src/rendermodes.h index a82dddb..23ada4c 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -83,13 +83,12 @@ void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject /* python metadata bindings */ PyObject *get_render_modes(PyObject *self, PyObject *args); PyObject *get_render_mode_info(PyObject *self, PyObject *args); -PyObject *get_render_mode_parent(PyObject *self, PyObject *args); PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args); PyObject *get_render_mode_children(PyObject *self, PyObject *args); -PyObject *get_render_mode_options(PyObject *self, PyObject *args); /* python rendermode options bindings */ PyObject *set_render_mode_options(PyObject *self, PyObject *args); +PyObject *add_custom_render_mode(PyObject *self, PyObject *args); /* individual rendermode interface declarations follow */ From f5a187dad086e5f57cd7a9a5a515b33babd7d8fc Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 11 Jun 2011 04:27:04 -0400 Subject: [PATCH 11/29] bumped extension version, and added in a few new rendermode options --- src/overviewer.h | 2 +- src/rendermode-cave.c | 40 ++++++++++++++++++++++++--------------- src/rendermode-lighting.c | 19 ++++++++++++++++++- src/rendermodes.h | 3 +++ 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/overviewer.h b/src/overviewer.h index 49e70fa..a0c5316 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 7 +#define OVERVIEWER_EXTENSION_VERSION 8 /* Python PIL, and numpy headers */ #include diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index e4275e5..b8fc370 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -17,19 +17,16 @@ #include "overviewer.h" #include -//~ -//~ /* figures out the black_coeff from a given skylight and blocklight, used in - //~ lighting calculations -- note this is *different* from the one in - //~ rendermode-lighting.c (the "skylight - 11" part) */ -//~ static float calculate_darkness(unsigned char skylight, unsigned char blocklight) { - //~ return 1.0f - powf(0.8f, 15.0 - MAX(blocklight, skylight - 11)); -//~ } static int rendermode_cave_occluded(void *data, RenderState *state) { int x = state->x, y = state->y, z = state->z, dz = 0; RenderModeCave* self; self = (RenderModeCave *)data; + + /* first, check to see if it's "normally" occluded */ + if (rendermode_normal.occluded(data, state)) + return 1; /* check if the block is touching skylight */ if (z != 127) { @@ -164,12 +161,20 @@ static int rendermode_cave_start(void *data, RenderState *state, PyObject *options) { RenderModeCave* self; int ret; + PyObject *opt; self = (RenderModeCave *)data; /* first, chain up */ ret = rendermode_normal.start(data, state, options); if (ret != 0) return ret; + + opt = PyDict_GetItemString(options, "depth_tinting"); + if (opt) { + self->depth_tinting = PyObject_IsTrue(opt); + } else { + self->depth_tinting = 1; + } /* if there's skylight we are in the surface! */ self->skylight = PyObject_GetAttrString(state->self, "skylight"); @@ -213,19 +218,24 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma /* draw the normal block */ rendermode_normal.draw(data, state, src, mask, mask_light); - /* get the colors and tint and tint */ - /* TODO TODO for a nether mode there isn't tinting! */ - r = PyInt_AsLong(PyList_GetItem(self->depth_colors, 0 + z*3)); - g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3)); - b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + z*3)); - - tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0); + if (self->depth_tinting) { + /* get the colors and tint and tint */ + r = PyInt_AsLong(PyList_GetItem(self->depth_colors, 0 + z*3)); + g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + z*3)); + b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + z*3)); + + tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0); + } } +static RenderModeOption rendermode_cave_options[] = { + {"depth_tinting", "tint caves based on how deep they are (default: True)"}, +}; + RenderModeInterface rendermode_cave = { "cave", "render only caves in normal mode", - NULL, + rendermode_cave_options, &rendermode_normal, sizeof(RenderModeCave), rendermode_cave_start, diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index f3e529b..c4029ae 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -165,11 +165,13 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state, } black_coeff = get_lighting_coefficient(self, state, x, y, z, NULL); + black_coeff *= self->shade_strength; alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0); } static int rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { + PyObject *opt; RenderModeLighting* self; /* first, chain up */ @@ -178,6 +180,17 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { return ret; self = (RenderModeLighting *)data; + + opt = PyDict_GetItemString(options, "shade_strength"); + if (opt) { + if (!PyNumber_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'shade_strength' must be a number"); + return 1; + } + self->shade_strength = PyFloat_AsDouble(opt); + } else { + self->shade_strength = 1.0; + } self->black_color = PyObject_GetAttrString(state->chunk, "black_color"); self->facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks"); @@ -244,9 +257,13 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject } } +RenderModeOption rendermode_lighting_options[] = { + {"shade_strength", "how dark to make the shadows, from 0.0 to 1.0 (default: 1.0)"}, +}; + RenderModeInterface rendermode_lighting = { "lighting", "draw shadows from the lighting data", - NULL, + rendermode_lighting_options, &rendermode_normal, sizeof(RenderModeLighting), rendermode_lighting_start, diff --git a/src/rendermodes.h b/src/rendermodes.h index 23ada4c..d5d3478 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -141,6 +141,8 @@ typedef struct { /* can be overridden in derived rendermodes to control lighting arguments are skylight, blocklight */ float (*calculate_darkness)(unsigned char, unsigned char); + + float shade_strength; } RenderModeLighting; extern RenderModeInterface rendermode_lighting; @@ -177,6 +179,7 @@ typedef struct { /* colors used for tinting */ PyObject *depth_colors; + int depth_tinting; } RenderModeCave; extern RenderModeInterface rendermode_cave; From 5ae843aa8047fb62add9f3d3f25e625c934ed643 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sat, 11 Jun 2011 04:38:38 -0400 Subject: [PATCH 12/29] fixed --list-rendermodes bug, and made sure custom modes show up --- overviewer.py | 6 +++++- src/rendermode-cave.c | 1 + src/rendermode-lighting.c | 1 + src/rendermode-normal.c | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index cea9bbb..c296c10 100755 --- a/overviewer.py +++ b/overviewer.py @@ -135,10 +135,14 @@ def main(): c_overviewer.set_render_mode_options(mode, options.rendermode_options[mode]) if options.list_rendermodes: + avail_rendermodes = c_overviewer.get_render_modes() rendermode_info = map(c_overviewer.get_render_mode_info, avail_rendermodes) name_width = max(map(lambda i: len(i['name']), rendermode_info)) for info in rendermode_info: - print "{name:{0}} {description}".format(name_width, **info) + if not 'description' in info: + print "{name:{0}} (no description)".format(name_width, **info) + else: + print "{name:{0}} {description}".format(name_width, **info) sys.exit(0) if len(args) < 1: diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index b8fc370..d5410ee 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -231,6 +231,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma static RenderModeOption rendermode_cave_options[] = { {"depth_tinting", "tint caves based on how deep they are (default: True)"}, + {NULL, NULL} }; RenderModeInterface rendermode_cave = { diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index c4029ae..8f27084 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -259,6 +259,7 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject RenderModeOption rendermode_lighting_options[] = { {"shade_strength", "how dark to make the shadows, from 0.0 to 1.0 (default: 1.0)"}, + {NULL, NULL} }; RenderModeInterface rendermode_lighting = { diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index a24bc80..c9ac6a8 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -288,6 +288,7 @@ static RenderModeOption rendermode_normal_options[] = { {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)"}, {"min_depth", "lowest level of blocks to render (default: 0)"}, {"max_depth", "highest level of blocks to render (default: 127)"}, + {NULL, NULL} }; RenderModeInterface rendermode_normal = { From 3d6042260c48678005b0d1990bdf6a1e999fa96f Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 12 Jun 2011 20:49:54 -0400 Subject: [PATCH 13/29] added 'only_lit' option to cave mode --- chunk.py | 14 +++++ src/rendermode-cave.c | 140 +++++++++++++++++++++++++++--------------- src/rendermodes.h | 8 +++ 3 files changed, 112 insertions(+), 50 deletions(-) diff --git a/chunk.py b/chunk.py index f8aa1f6..a4b8bf6 100644 --- a/chunk.py +++ b/chunk.py @@ -294,6 +294,13 @@ class ChunkRenderer(object): return self._up_right_skylight up_right_skylight = property(_load_up_right_skylight) + def _load_up_right_blocklight(self): + """Loads and returns lower-right blocklight array""" + if not hasattr(self, "_up_right_blocklight"): + self._load_up_right() + return self._up_right_blocklight + up_right_blocklight = property(_load_up_right_blocklight) + def _load_up_left(self): """Loads and sets data from upper-left chunk""" chunk_path = self.world.get_region_path(self.chunkX, self.chunkY - 1) @@ -321,6 +328,13 @@ class ChunkRenderer(object): return self._up_left_skylight up_left_skylight = property(_load_up_left_skylight) + def _load_up_left_blocklight(self): + """Loads and returns lower-left blocklight array""" + if not hasattr(self, "_up_left_blocklight"): + self._load_up_left() + return self._up_left_blocklight + up_left_blocklight = property(_load_up_left_blocklight) + def generate_pseudo_ancildata(self,x,y,z,blockid, north_position = 0 ): """ Generates a pseudo ancillary data for blocks that depend of what are surrounded and don't have ancillary data diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index d5410ee..012a305 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -18,6 +18,67 @@ #include "overviewer.h" #include +static inline int +touches_light(unsigned int x, unsigned int y, unsigned int z, + PyObject *light, PyObject *left_light, PyObject *right_light, + PyObject *up_left_light, PyObject *up_right_light) { + + + if (getArrayByte3D(light, x, y, z+1) != 0) { + return 1; + } + + if ((x == 15)) { + if (up_right_light != Py_None) { + if (getArrayByte3D(up_right_light, 0, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(light, x+1, y, z) != 0) { + return 1; + } + } + + if (x == 0) { + if (left_light != Py_None) { + if (getArrayByte3D(left_light, 15, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(light, x-1, y, z) != 0) { + return 1; + } + } + + if (y == 15) { + if (right_light != Py_None) { + if (getArrayByte3D(right_light, 0, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(light, x, y+1, z) != 0) { + return 1; + } + } + + if (y == 0) { + if (up_left_light != Py_None) { + if (getArrayByte3D(up_left_light, 15, y, z) != 0) { + return 1; + } + } + } else { + if (getArrayByte3D(light, x, y-1, z) != 0) { + return 1; + } + } + + return 0; +} + static int rendermode_cave_occluded(void *data, RenderState *state) { int x = state->x, y = state->y, z = state->z, dz = 0; @@ -31,56 +92,12 @@ rendermode_cave_occluded(void *data, RenderState *state) { /* check if the block is touching skylight */ if (z != 127) { - if (getArrayByte3D(self->skylight, x, y, z+1) != 0) { + if (touches_light(x, y, z, self->skylight, self->left_skylight, self->right_skylight, self->up_left_skylight, self->up_right_skylight)) { return 1; } - if ((x == 15)) { - if (self->up_right_skylight != Py_None) { - if (getArrayByte3D(self->up_right_skylight, 0, y, z) != 0) { - return 1; - } - } - } else { - if (getArrayByte3D(self->skylight, x+1, y, z) != 0) { - return 1; - } - } - - if (x == 0) { - if (self->left_skylight != Py_None) { - if (getArrayByte3D(self->left_skylight, 15, y, z) != 0) { - return 1; - } - } - } else { - if (getArrayByte3D(self->skylight, x-1, y, z) != 0) { - return 1; - } - } - - if (y == 15) { - if (self->right_skylight != Py_None) { - if (getArrayByte3D(self->right_skylight, 0, y, z) != 0) { - return 1; - } - } - } else { - if (getArrayByte3D(self->skylight, x, y+1, z) != 0) { - return 1; - } - } - - if (y == 0) { - if (self->up_left_skylight != Py_None) { - if (getArrayByte3D(self->up_left_skylight, 15, y, z) != 0) { - return 1; - } - } - } else { - if (getArrayByte3D(self->skylight, x, y-1, z) != 0) { - return 1; - } + if (self->only_lit && !touches_light(x, y, z, self->blocklight, self->left_blocklight, self->right_blocklight, self->up_left_blocklight, self->up_right_blocklight)) { + return 1; } /* check for normal occlusion */ @@ -176,17 +193,31 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) { self->depth_tinting = 1; } + opt = PyDict_GetItemString(options, "only_lit"); + if (opt) { + self->only_lit = PyObject_IsTrue(opt); + } else { + self->only_lit = 0; + } + /* if there's skylight we are in the surface! */ self->skylight = PyObject_GetAttrString(state->self, "skylight"); self->left_skylight = PyObject_GetAttrString(state->self, "left_skylight"); self->right_skylight = PyObject_GetAttrString(state->self, "right_skylight"); self->up_left_skylight = PyObject_GetAttrString(state->self, "up_left_skylight"); self->up_right_skylight = PyObject_GetAttrString(state->self, "up_right_skylight"); + + if (self->only_lit) { + self->blocklight = PyObject_GetAttrString(state->self, "blocklight"); + self->left_blocklight = PyObject_GetAttrString(state->self, "left_blocklight"); + self->right_blocklight = PyObject_GetAttrString(state->self, "right_blocklight"); + self->up_left_blocklight = PyObject_GetAttrString(state->self, "up_left_blocklight"); + self->up_right_blocklight = PyObject_GetAttrString(state->self, "up_right_blocklight"); + } /* colors for tinting */ self->depth_colors = PyObject_GetAttrString(state->chunk, "depth_colors"); - return 0; } @@ -194,13 +225,21 @@ static void rendermode_cave_finish(void *data, RenderState *state) { RenderModeCave* self; self = (RenderModeCave *)data; - + Py_DECREF(self->skylight); Py_DECREF(self->left_skylight); Py_DECREF(self->right_skylight); Py_DECREF(self->up_left_skylight); Py_DECREF(self->up_right_skylight); - + + if (self->only_lit) { + Py_DECREF(self->blocklight); + Py_DECREF(self->left_blocklight); + Py_DECREF(self->right_blocklight); + Py_DECREF(self->up_left_blocklight); + Py_DECREF(self->up_right_blocklight); + } + Py_DECREF(self->depth_colors); rendermode_normal.finish(data, state); @@ -231,6 +270,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma static RenderModeOption rendermode_cave_options[] = { {"depth_tinting", "tint caves based on how deep they are (default: True)"}, + {"only_lit", "only render lit caves (default: False)"}, {NULL, NULL} }; diff --git a/src/rendermodes.h b/src/rendermodes.h index d5d3478..928c0ac 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -176,10 +176,18 @@ typedef struct { PyObject *up_left_skylight; PyObject *up_right_skylight; + /* data used to know where the surface is */ + PyObject *blocklight; + PyObject *left_blocklight; + PyObject *right_blocklight; + PyObject *up_left_blocklight; + PyObject *up_right_blocklight; + /* colors used for tinting */ PyObject *depth_colors; int depth_tinting; + int only_lit; } RenderModeCave; extern RenderModeInterface rendermode_cave; From bdee43806012c331ebcca88d025d686ae5295a52 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 12 Jun 2011 22:03:42 -0400 Subject: [PATCH 14/29] added 'lighting' option to cave mode --- chunk.py | 4 ++++ src/iterate.c | 4 ++-- src/overviewer.h | 6 ++++++ src/rendermode-cave.c | 28 ++++++++++++++++++++-------- src/rendermode-lighting.c | 17 +++++++---------- src/rendermode-night.c | 4 ++-- src/rendermode-normal.c | 3 +-- src/rendermode-overlay.c | 4 +--- src/rendermode-spawn.c | 4 ++-- src/rendermodes.c | 4 ++-- src/rendermodes.h | 12 +++++++----- 11 files changed, 54 insertions(+), 36 deletions(-) diff --git a/chunk.py b/chunk.py index a4b8bf6..1a1ad14 100644 --- a/chunk.py +++ b/chunk.py @@ -476,6 +476,10 @@ def generate_facemasks(): for x,y in [(3,4), (7,2), (11,0)]: top.putpixel((x,y), 255) + # special fix for chunk boundary stipple + for x,y in [(13,11), (17,9), (21,7)]: + right.putpixel((x,y), 0) + return (top, left, right) facemasks = generate_facemasks() black_color = Image.new("RGB", (24,24), (0,0,0)) diff --git a/src/iterate.c b/src/iterate.c index 5d82aaa..ca56f9b 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -317,7 +317,7 @@ chunk_render(PyObject *self, PyObject *args) { /* set up the render mode */ rendermode_py = PyObject_GetAttrString(state.self, "rendermode"); - rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); + state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); Py_DECREF(rendermode_py); if (rendermode == NULL) { return Py_BuildValue("i", "-1"); @@ -386,7 +386,7 @@ chunk_render(PyObject *self, PyObject *args) { blockid = PyInt_FromLong(state.block); // check for occlusion - if (render_mode_occluded(rendermode)) { + if (render_mode_occluded(rendermode, state.x, state.y, state.z)) { continue; } diff --git a/src/overviewer.h b/src/overviewer.h index a0c5316..9befb18 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -52,6 +52,9 @@ PyObject *tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa, PyObject *mask, int dx, int dy, int xsize, int ysize); +/* forward declaration of RenderMode object */ +typedef struct _RenderMode RenderMode; + /* in iterate.c */ typedef struct { /* the ChunkRenderer object */ @@ -61,6 +64,9 @@ typedef struct { PyObject *textures; PyObject *chunk; + /* the current render mode in use */ + RenderMode *rendermode; + /* the rest only make sense for occluded() and draw() !! */ /* the tile image and destination */ diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index 012a305..6d8a7cb 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -80,13 +80,13 @@ touches_light(unsigned int x, unsigned int y, unsigned int z, } static int -rendermode_cave_occluded(void *data, RenderState *state) { - int x = state->x, y = state->y, z = state->z, dz = 0; +rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { RenderModeCave* self; + int dz = 0; self = (RenderModeCave *)data; /* first, check to see if it's "normally" occluded */ - if (rendermode_normal.occluded(data, state)) + if (rendermode_lighting.occluded(data, state, x, y, z)) return 1; /* check if the block is touching skylight */ @@ -182,7 +182,7 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) { self = (RenderModeCave *)data; /* first, chain up */ - ret = rendermode_normal.start(data, state, options); + ret = rendermode_lighting.start(data, state, options); if (ret != 0) return ret; @@ -200,6 +200,13 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) { self->only_lit = 0; } + opt = PyDict_GetItemString(options, "lighting"); + if (opt) { + self->lighting = PyObject_IsTrue(opt); + } else { + self->lighting = 0; + } + /* if there's skylight we are in the surface! */ self->skylight = PyObject_GetAttrString(state->self, "skylight"); self->left_skylight = PyObject_GetAttrString(state->self, "left_skylight"); @@ -242,7 +249,7 @@ rendermode_cave_finish(void *data, RenderState *state) { Py_DECREF(self->depth_colors); - rendermode_normal.finish(data, state); + rendermode_lighting.finish(data, state); } static void @@ -255,7 +262,11 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma r = 0, g = 0, b = 0; /* draw the normal block */ - rendermode_normal.draw(data, state, src, mask, mask_light); + if (self->lighting) { + rendermode_lighting.draw(data, state, src, mask, mask_light); + } else { + rendermode_normal.draw(data, state, src, mask, mask_light); + } if (self->depth_tinting) { /* get the colors and tint and tint */ @@ -271,13 +282,14 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma static RenderModeOption rendermode_cave_options[] = { {"depth_tinting", "tint caves based on how deep they are (default: True)"}, {"only_lit", "only render lit caves (default: False)"}, + {"lighting", "render caves with lighting enabled (default: False)"}, {NULL, NULL} }; RenderModeInterface rendermode_cave = { - "cave", "render only caves in normal mode", + "cave", "render only caves", rendermode_cave_options, - &rendermode_normal, + &rendermode_lighting, sizeof(RenderModeCave), rendermode_cave_start, rendermode_cave_finish, diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index 8f27084..f4c8bc6 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -83,12 +83,6 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state, block = getArrayByte3D(blocks, local_x, local_y, local_z); - /* if this block is opaque, use a fully-lit coeff instead - to prevent stippled lines along chunk boundaries! */ - if (!is_transparent(block)) { - return self->calculate_darkness(15, 0); - } - /* only do special half-step handling if no authoratative pointer was passed in, which is a sign that we're recursing */ if ((block == 44 || block == 53 || block == 67) && authoratative == NULL) { @@ -154,11 +148,14 @@ static inline void do_shading_with_mask(RenderModeLighting *self, RenderState *state, int x, int y, int z, PyObject *mask) { float black_coeff; - + PyObject *blocks; + /* first, check for occlusion if the block is in the local chunk */ if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) { unsigned char block = getArrayByte3D(state->blocks, x, y, z); - if (!is_transparent(block)) { + int occluded = render_mode_occluded(state->rendermode, x, y, z); + + if (!occluded && !is_transparent(block)) { /* this face isn't visible, so don't draw anything */ return; } @@ -230,9 +227,9 @@ rendermode_lighting_finish(void *data, RenderState *state) { } static int -rendermode_lighting_occluded(void *data, RenderState *state) { +rendermode_lighting_occluded(void *data, RenderState *state, int x, int y, int z) { /* no special occlusion here */ - return rendermode_normal.occluded(data, state); + return rendermode_normal.occluded(data, state, x, y, z); } static void diff --git a/src/rendermode-night.c b/src/rendermode-night.c index f3edc68..f1d38bd 100644 --- a/src/rendermode-night.c +++ b/src/rendermode-night.c @@ -48,9 +48,9 @@ rendermode_night_finish(void *data, RenderState *state) { } static int -rendermode_night_occluded(void *data, RenderState *state) { +rendermode_night_occluded(void *data, RenderState *state, int x, int y, int z) { /* no special occlusion here */ - return rendermode_lighting.occluded(data, state); + return rendermode_lighting.occluded(data, state, x, y, z); } static void diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index c9ac6a8..85c01ac 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -144,9 +144,8 @@ rendermode_normal_finish(void *data, RenderState *state) { } static int -rendermode_normal_occluded(void *data, RenderState *state) { +rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) { RenderModeNormal *self = (RenderModeNormal *)data; - int x = state->x, y = state->y, z = state->z; if (z > self->max_depth || z < self->min_depth) { return 1; diff --git a/src/rendermode-overlay.c b/src/rendermode-overlay.c index 342a6f9..769c445 100644 --- a/src/rendermode-overlay.c +++ b/src/rendermode-overlay.c @@ -57,9 +57,7 @@ rendermode_overlay_finish(void *data, RenderState *state) { } static int -rendermode_overlay_occluded(void *data, RenderState *state) { - int x = state->x, y = state->y, z = state->z; - +rendermode_overlay_occluded(void *data, RenderState *state, int x, int y, int z) { if ( (x != 0) && (y != 15) && (z != 127) && !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && diff --git a/src/rendermode-spawn.c b/src/rendermode-spawn.c index 4fff748..b812444 100644 --- a/src/rendermode-spawn.c +++ b/src/rendermode-spawn.c @@ -96,9 +96,9 @@ rendermode_spawn_finish(void *data, RenderState *state) { } static int -rendermode_spawn_occluded(void *data, RenderState *state) { +rendermode_spawn_occluded(void *data, RenderState *state, int x, int y, int z) { /* no special occlusion here */ - return rendermode_overlay.occluded(data, state); + return rendermode_overlay.occluded(data, state, x, y, z); } static void diff --git a/src/rendermodes.c b/src/rendermodes.c index eb88517..e03921c 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -164,8 +164,8 @@ void render_mode_destroy(RenderMode *self) { free(self); } -int render_mode_occluded(RenderMode *self) { - return self->iface->occluded(self->mode, self->state); +int render_mode_occluded(RenderMode *self, int x, int y, int z) { + return self->iface->occluded(self->mode, self->state, x, y, z); } void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light) { diff --git a/src/rendermodes.h b/src/rendermodes.h index 928c0ac..120726c 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -36,6 +36,7 @@ #define __RENDERMODES_H_INCLUDED__ #include +#include "overviewer.h" typedef struct { const char *name; @@ -62,22 +63,22 @@ struct _RenderModeInterface { int (*start)(void *, RenderState *, PyObject *); void (*finish)(void *, RenderState *); /* returns non-zero to skip rendering this block */ - int (*occluded)(void *, RenderState *); + int (*occluded)(void *, RenderState *, int, int, int); /* last two arguments are img and mask, from texture lookup */ void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *); }; /* wrapper for passing around rendermodes */ -typedef struct { +struct _RenderMode { void *mode; RenderModeInterface *iface; RenderState *state; -} RenderMode; +}; /* functions for creating / using rendermodes */ RenderMode *render_mode_create(const char *mode, RenderState *state); void render_mode_destroy(RenderMode *self); -int render_mode_occluded(RenderMode *self); +int render_mode_occluded(RenderMode *self, int x, int y, int z); void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light); /* python metadata bindings */ @@ -167,7 +168,7 @@ extern RenderModeInterface rendermode_spawn; /* CAVE */ typedef struct { /* render blocks with lighting mode */ - RenderModeNormal parent; + RenderModeLighting parent; /* data used to know where the surface is */ PyObject *skylight; @@ -188,6 +189,7 @@ typedef struct { int depth_tinting; int only_lit; + int lighting; } RenderModeCave; extern RenderModeInterface rendermode_cave; From 98562b6f4a14b9f5b3319d3b49d6f57c814fb8e3 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 12 Jun 2011 22:29:28 -0400 Subject: [PATCH 15/29] windows build fixes --- src/rendermode-cave.c | 2 +- src/rendermode-lighting.c | 2 +- src/rendermode-normal.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index 6d8a7cb..c29a8a5 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -279,7 +279,7 @@ rendermode_cave_draw(void *data, RenderState *state, PyObject *src, PyObject *ma } -static RenderModeOption rendermode_cave_options[] = { +const RenderModeOption rendermode_cave_options[] = { {"depth_tinting", "tint caves based on how deep they are (default: True)"}, {"only_lit", "only render lit caves (default: False)"}, {"lighting", "render caves with lighting enabled (default: False)"}, diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index f4c8bc6..88c8d57 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -254,7 +254,7 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject } } -RenderModeOption rendermode_lighting_options[] = { +const RenderModeOption rendermode_lighting_options[] = { {"shade_strength", "how dark to make the shadows, from 0.0 to 1.0 (default: 1.0)"}, {NULL, NULL} }; diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index e27f84e..0d41ed4 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -284,7 +284,7 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * } } -static RenderModeOption rendermode_normal_options[] = { +const RenderModeOption rendermode_normal_options[] = { {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)"}, {"min_depth", "lowest level of blocks to render (default: 0)"}, {"max_depth", "highest level of blocks to render (default: 127)"}, From a50cd315ef417f3716cf4f2d3a128ace78d32b32 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Tue, 14 Jun 2011 20:56:21 -0400 Subject: [PATCH 16/29] added 'minerals' option to mineral overlay --- src/rendermode-mineral.c | 63 +++++++++++++++++++++++++++++++++------- src/rendermodes.h | 2 ++ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c index 07d8701..5ba4f1e 100644 --- a/src/rendermode-mineral.c +++ b/src/rendermode-mineral.c @@ -17,13 +17,13 @@ #include "overviewer.h" -struct OreColor { +struct MineralColor { unsigned char blockid; unsigned char r, g, b; }; /* put more valuable ores first -- they take precedence */ -static struct OreColor orecolors[] = { +static struct MineralColor default_minerals[] = { {48 /* Mossy Stone */, 31, 153, 9}, {56 /* Diamond Ore */, 32, 230, 220}, @@ -44,18 +44,20 @@ static void get_color(void *data, RenderState *state, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { int x = state->x, y = state->y, z_max = state->z, z; - //RenderModeMineral* self = (RenderModeMineral *)data; + int max_i = -1; + RenderModeMineral* self = (RenderModeMineral *)data; + struct MineralColor *minerals = (struct MineralColor *)(self->minerals); *a = 0; for (z = 0; z <= z_max; z++) { - int i, tmp, max_i = sizeof(orecolors) / sizeof(struct OreColor); + int i, tmp; unsigned char blockid = getArrayByte3D(state->blocks, x, y, z); - for (i = 0; i < max_i && orecolors[i].blockid != 0; i++) { - if (orecolors[i].blockid == blockid) { - *r = orecolors[i].r; - *g = orecolors[i].g; - *b = orecolors[i].b; + for (i = 0; (max_i == -1 || i < max_i) && minerals[i].blockid != 0; i++) { + if (minerals[i].blockid == blockid) { + *r = minerals[i].r; + *g = minerals[i].g; + *b = minerals[i].b; tmp = (128 - z_max + z) * 2 - 40; *a = MIN(MAX(0, tmp), 255); @@ -69,6 +71,7 @@ static void get_color(void *data, RenderState *state, static int rendermode_mineral_start(void *data, RenderState *state, PyObject *options) { + PyObject *opt; RenderModeMineral* self; /* first, chain up */ @@ -79,6 +82,35 @@ rendermode_mineral_start(void *data, RenderState *state, PyObject *options) { /* now do custom initializations */ self = (RenderModeMineral *)data; + opt = PyDict_GetItemString(options, "minerals"); + if (opt) { + struct MineralColor *minerals = NULL; + Py_ssize_t minerals_size = 0, i; + /* create custom minerals */ + + if (!PyList_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'minerals' must be a list"); + return 1; + } + + minerals_size = PyList_GET_SIZE(opt); + minerals = self->minerals = calloc(minerals_size + 1, sizeof(struct MineralColor)); + if (minerals == NULL) { + return 1; + } + + for (i = 0; i < minerals_size; i++) { + PyObject *mineral = PyList_GET_ITEM(opt, i); + if (!PyArg_ParseTuple(mineral, "b(bbb)", &(minerals[i].blockid), &(minerals[i].r), &(minerals[i].g), &(minerals[i].b))) { + free(minerals); + self->minerals = NULL; + return 1; + } + } + } else { + self->minerals = default_minerals; + } + /* setup custom color */ self->parent.get_color = get_color; @@ -88,7 +120,11 @@ rendermode_mineral_start(void *data, RenderState *state, PyObject *options) { static void rendermode_mineral_finish(void *data, RenderState *state) { /* first free all *our* stuff */ - //RenderModeMineral* self = (RenderModeMineral *)data; + RenderModeMineral* self = (RenderModeMineral *)data; + + if (self->minerals && self->minerals != default_minerals) { + free(self->minerals); + } /* now, chain up */ rendermode_overlay.finish(data, state); @@ -106,9 +142,14 @@ rendermode_mineral_draw(void *data, RenderState *state, PyObject *src, PyObject rendermode_overlay.draw(data, state, src, mask, mask_light); } +const RenderModeOption rendermode_mineral_options[] = { + {"minerals", "a list of (blockid, (r, g, b)) tuples for coloring minerals"}, + {NULL, NULL} +}; + RenderModeInterface rendermode_mineral = { "mineral", "draws a colored overlay showing where ores are located", - NULL, + rendermode_mineral_options, &rendermode_overlay, sizeof(RenderModeMineral), rendermode_mineral_start, diff --git a/src/rendermodes.h b/src/rendermodes.h index 6bbf5bb..c867bf2 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -197,6 +197,8 @@ extern RenderModeInterface rendermode_cave; typedef struct { /* inherits from overlay */ RenderModeOverlay parent; + + void *minerals; } RenderModeMineral; extern RenderModeInterface rendermode_mineral; From 7d587ecc6df063815a1779f27955c5171e9e7f5b Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Tue, 14 Jun 2011 21:13:53 -0400 Subject: [PATCH 17/29] changed mineral overlay to highlight even if the block is just above the color --- src/rendermode-mineral.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendermode-mineral.c b/src/rendermode-mineral.c index 5ba4f1e..3a74d5a 100644 --- a/src/rendermode-mineral.c +++ b/src/rendermode-mineral.c @@ -43,7 +43,7 @@ static struct MineralColor default_minerals[] = { static void get_color(void *data, RenderState *state, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { - int x = state->x, y = state->y, z_max = state->z, z; + int x = state->x, y = state->y, z_max = state->z + 1, z; int max_i = -1; RenderModeMineral* self = (RenderModeMineral *)data; struct MineralColor *minerals = (struct MineralColor *)(self->minerals); From 57100c1912459cd6dbae7d1b83146d490c5f960c Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 15 Jun 2011 00:42:41 -0400 Subject: [PATCH 18/29] fix small bug when parent option merging fails --- src/rendermodes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rendermodes.c b/src/rendermodes.c index 77a9196..29c506e 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -80,6 +80,7 @@ render_mode_create_options(const char *mode) { parent_options = render_mode_create_options(parent); if (parent_options) { if (PyDict_Merge(ret, parent_options, 0) == -1) { + Py_DECREF(ret); Py_DECREF(parent_options); return NULL; } From f8b005d0796853093e83411d8eafb43293cc5491 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 19 Jun 2011 13:06:12 -0400 Subject: [PATCH 19/29] added render_mode_parse_option helper function --- src/iterate.c | 2 +- src/rendermode-cave.c | 30 +++++++++----------------- src/rendermode-lighting.c | 14 +++--------- src/rendermode-normal.c | 43 ++++++++++--------------------------- src/rendermodes.c | 45 +++++++++++++++++++++++++++++++++++++++ src/rendermodes.h | 4 ++++ 6 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/iterate.c b/src/iterate.c index ca56f9b..208e147 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -320,7 +320,7 @@ chunk_render(PyObject *self, PyObject *args) { state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); Py_DECREF(rendermode_py); if (rendermode == NULL) { - return Py_BuildValue("i", "-1"); + return NULL; } /* get the image size */ diff --git a/src/rendermode-cave.c b/src/rendermode-cave.c index c29a8a5..e68578f 100644 --- a/src/rendermode-cave.c +++ b/src/rendermode-cave.c @@ -178,7 +178,6 @@ static int rendermode_cave_start(void *data, RenderState *state, PyObject *options) { RenderModeCave* self; int ret; - PyObject *opt; self = (RenderModeCave *)data; /* first, chain up */ @@ -186,26 +185,17 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) { if (ret != 0) return ret; - opt = PyDict_GetItemString(options, "depth_tinting"); - if (opt) { - self->depth_tinting = PyObject_IsTrue(opt); - } else { - self->depth_tinting = 1; - } + self->depth_tinting = 1; + if (!render_mode_parse_option(options, "depth_tinting", "i", &(self->depth_tinting))) + return 1; - opt = PyDict_GetItemString(options, "only_lit"); - if (opt) { - self->only_lit = PyObject_IsTrue(opt); - } else { - self->only_lit = 0; - } - - opt = PyDict_GetItemString(options, "lighting"); - if (opt) { - self->lighting = PyObject_IsTrue(opt); - } else { - self->lighting = 0; - } + self->only_lit = 0; + if (!render_mode_parse_option(options, "only_lit", "i", &(self->only_lit))) + return 1; + + self->lighting = 0; + if (!render_mode_parse_option(options, "lighting", "i", &(self->lighting))) + return 1; /* if there's skylight we are in the surface! */ self->skylight = PyObject_GetAttrString(state->self, "skylight"); diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c index 88c8d57..6285724 100644 --- a/src/rendermode-lighting.c +++ b/src/rendermode-lighting.c @@ -168,7 +168,6 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state, static int rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { - PyObject *opt; RenderModeLighting* self; /* first, chain up */ @@ -178,16 +177,9 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { self = (RenderModeLighting *)data; - opt = PyDict_GetItemString(options, "shade_strength"); - if (opt) { - if (!PyNumber_Check(opt)) { - PyErr_SetString(PyExc_TypeError, "'shade_strength' must be a number"); - return 1; - } - self->shade_strength = PyFloat_AsDouble(opt); - } else { - self->shade_strength = 1.0; - } + self->shade_strength = 1.0; + if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength))) + return 1; self->black_color = PyObject_GetAttrString(state->chunk, "black_color"); self->facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks"); diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index 0d41ed4..bf72fc7 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -19,44 +19,23 @@ static int rendermode_normal_start(void *data, RenderState *state, PyObject *options) { - PyObject *opt, *chunk_x_py, *chunk_y_py, *world, *use_biomes, *worlddir; + PyObject *chunk_x_py, *chunk_y_py, *world, *use_biomes, *worlddir; RenderModeNormal *self = (RenderModeNormal *)data; /* load up the given options, first */ - opt = PyDict_GetItemString(options, "edge_opacity"); - if (opt) { - if (!PyNumber_Check(opt)) { - PyErr_SetString(PyExc_TypeError, "'edge_opacity' must be a number"); - return 1; - } - self->edge_opacity = PyFloat_AsDouble(opt); - } else { - self->edge_opacity = 0.15; - } + self->edge_opacity = 0.15; + if (!render_mode_parse_option(options, "edge_opacity", "f", &(self->edge_opacity))) + return 1; - opt = PyDict_GetItemString(options, "min_depth"); - if (opt) { - if (!PyInt_Check(opt)) { - PyErr_SetString(PyExc_TypeError, "'min_depth' must be an integer"); - return 1; - } - self->min_depth = PyInt_AsLong(opt); - } else { - self->min_depth = 0; - } + self->min_depth = 0; + if (!render_mode_parse_option(options, "min_depth", "I", &(self->min_depth))) + return 1; + + self->max_depth = 127; + if (!render_mode_parse_option(options, "max_depth", "I", &(self->max_depth))) + return 1; - opt = PyDict_GetItemString(options, "max_depth"); - if (opt) { - if (!PyInt_Check(opt)) { - PyErr_SetString(PyExc_TypeError, "'max_depth' must be an integer"); - return 1; - } - self->max_depth = PyInt_AsLong(opt); - } else { - self->max_depth = 127; - } - chunk_x_py = PyObject_GetAttrString(state->self, "chunkX"); chunk_y_py = PyObject_GetAttrString(state->self, "chunkY"); diff --git a/src/rendermodes.c b/src/rendermodes.c index 29c506e..717273c 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -17,6 +17,7 @@ #include "overviewer.h" #include +#include /* list of all render modes, ending in NULL all of these will be available to the user, so DON'T include modes @@ -174,6 +175,50 @@ void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject self->iface->draw(self->mode, self->state, img, mask, mask_light); } +/* options parse helper */ +int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...) { + va_list ap; + PyObject *item; + int ret; + + if (dict == NULL || name == NULL) + return 1; + + item = PyDict_GetItemString(dict, name); + if (item == NULL) + return 1; + + /* make sure the item we're parsing is a tuple + for VaParse to work correctly */ + if (!PyTuple_Check(item)) { + item = PyTuple_Pack(1, item); + } else { + Py_INCREF(item); + } + + va_start(ap, format); + ret = PyArg_VaParse(item, format, ap); + va_end(ap); + + Py_DECREF(item); + + if (!ret) { + PyObject *errtype, *errvalue, *errtraceback; + const char *errstring; + + PyErr_Fetch(&errtype, &errvalue, &errtraceback); + errstring = PyString_AsString(errvalue); + + PyErr_Format(PyExc_TypeError, "rendermode option \"%s\" has incorrect type (%s)", name, errstring); + + Py_DECREF(errtype); + Py_DECREF(errvalue); + Py_XDECREF(errtraceback); + } + + return ret; +} + /* bindings for python -- get all the rendermode names */ PyObject *get_render_modes(PyObject *self, PyObject *args) { PyObject *modes; diff --git a/src/rendermodes.h b/src/rendermodes.h index c867bf2..e27cb15 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -81,6 +81,10 @@ void render_mode_destroy(RenderMode *self); int render_mode_occluded(RenderMode *self, int x, int y, int z); void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light); +/* helper function for reading in rendermode options + works like PyArg_ParseTuple on a dictionary item */ +int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...); + /* python metadata bindings */ PyObject *get_render_modes(PyObject *self, PyObject *args); PyObject *get_render_mode_info(PyObject *self, PyObject *args); From 7e5f5189587b285d035c015cb3cc088344b21495 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 19 Jun 2011 13:34:16 -0400 Subject: [PATCH 20/29] normal mode height fading (a la Fenixin's formula, Issue #147) --- src/rendermode-normal.c | 28 +++++++++++++++++++++++++++- src/rendermodes.h | 4 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/rendermode-normal.c b/src/rendermode-normal.c index bf72fc7..9d79f68 100644 --- a/src/rendermode-normal.c +++ b/src/rendermode-normal.c @@ -36,6 +36,15 @@ rendermode_normal_start(void *data, RenderState *state, PyObject *options) { if (!render_mode_parse_option(options, "max_depth", "I", &(self->max_depth))) return 1; + self->height_fading = 0; + if (!render_mode_parse_option(options, "height_fading", "i", &(self->height_fading))) + return 1; + + if (self->height_fading) { + self->black_color = PyObject_GetAttrString(state->chunk, "black_color"); + self->white_color = PyObject_GetAttrString(state->chunk, "white_color"); + } + chunk_x_py = PyObject_GetAttrString(state->self, "chunkX"); chunk_y_py = PyObject_GetAttrString(state->self, "chunkY"); @@ -120,6 +129,8 @@ rendermode_normal_finish(void *data, RenderState *state) { Py_XDECREF(self->tall_grass_texture); Py_XDECREF(self->tall_fern_texture); Py_XDECREF(self->facemask_top); + Py_XDECREF(self->black_color); + Py_XDECREF(self->white_color); } static int @@ -216,7 +227,21 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject * tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0); } } - + + if (self->height_fading) { + /* do some height fading */ + PyObject *height_color = self->white_color; + /* negative alpha => darkness, positive => light */ + float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55; + + if (alpha < 0.0) { + alpha *= -1; + height_color = self->black_color; + } + + alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0); + } + /* Draw some edge lines! */ // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) @@ -267,6 +292,7 @@ const RenderModeOption rendermode_normal_options[] = { {"edge_opacity", "darkness of the edge lines, from 0.0 to 1.0 (default: 0.15)"}, {"min_depth", "lowest level of blocks to render (default: 0)"}, {"max_depth", "highest level of blocks to render (default: 127)"}, + {"height_fading", "darken or lighten blocks based on height (default: False)"}, {NULL, NULL} }; diff --git a/src/rendermodes.h b/src/rendermodes.h index e27cb15..52473f3 100644 --- a/src/rendermodes.h +++ b/src/rendermodes.h @@ -110,9 +110,13 @@ typedef struct { /* top facemask for grass biome tinting */ PyObject *facemask_top; + /* black and white colors for height fading */ + PyObject *black_color, *white_color; + float edge_opacity; unsigned int min_depth; unsigned int max_depth; + int height_fading; } RenderModeNormal; extern RenderModeInterface rendermode_normal; From d5ceec6e8b3071eec6a91c6efe0a439206f62a88 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 19 Jun 2011 13:50:55 -0400 Subject: [PATCH 21/29] fixed custom mode option inheritance bug + another bug Render mode "self" structs are now guaranteed to start zero'd out. --- src/rendermodes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rendermodes.c b/src/rendermodes.c index 717273c..ed02a55 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -66,7 +66,7 @@ render_mode_create_options(const char *mode) { } /* check custom mode info if needed */ - if (found_concrete == 1 && custom_render_modes != NULL) { + if (found_concrete == 0 && custom_render_modes != NULL) { PyObject *custom = PyDict_GetItemString(custom_render_modes, mode); if (custom) { custom = PyDict_GetItemString(custom, "parent"); @@ -134,13 +134,13 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) { if (options == NULL) return NULL; - ret = malloc(sizeof(RenderMode)); + ret = calloc(1, sizeof(RenderMode)); if (ret == NULL) { Py_DECREF(options); return NULL; } - ret->mode = malloc(iface->data_size); + ret->mode = calloc(1, iface->data_size); if (ret->mode == NULL) { Py_DECREF(options); free(ret); From 931d71103c82cc13f69fe89f4d97f59cdf6d22df Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 18 Jul 2011 23:56:51 -0400 Subject: [PATCH 22/29] possible (hopeful) fix for the garbage collection bug --- overviewer_core/src/main.c | 19 +++++- overviewer_core/src/rendermodes.c | 96 +++++++++++++------------------ 2 files changed, 57 insertions(+), 58 deletions(-) diff --git a/overviewer_core/src/main.c b/overviewer_core/src/main.c index 0adb883..b2578e8 100644 --- a/overviewer_core/src/main.c +++ b/overviewer_core/src/main.c @@ -17,6 +17,10 @@ #include "overviewer.h" +/* global variables from rendermodes.c -- both are dictionaries */ +extern PyObject *render_mode_options; +extern PyObject *custom_render_modes; + PyObject *get_extension_version(PyObject *self, PyObject *args) { return Py_BuildValue("i", OVERVIEWER_EXTENSION_VERSION); @@ -55,9 +59,22 @@ static PyMethodDef COverviewerMethods[] = { PyMODINIT_FUNC initc_overviewer(void) { - (void)Py_InitModule("c_overviewer", COverviewerMethods); + PyObject *mod = Py_InitModule("c_overviewer", COverviewerMethods); + /* for numpy */ import_array(); + /* create the render mode data structures, and attatch them to the module + * so that the Python garbage collector doesn't freak out + */ + + render_mode_options = PyDict_New(); + PyObject_SetAttrString(mod, "_render_mode_options", render_mode_options); + Py_DECREF(render_mode_options); + + custom_render_modes = PyDict_New(); + PyObject_SetAttrString(mod, "_custom_render_modes", custom_render_modes); + Py_DECREF(custom_render_modes); + init_endian(); } diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index ed02a55..075fb27 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -32,8 +32,8 @@ static RenderModeInterface *render_modes[] = { NULL }; -static PyObject *render_mode_options = NULL; -static PyObject *custom_render_modes = NULL; +PyObject *render_mode_options = NULL; +PyObject *custom_render_modes = NULL; /* rendermode encapsulation */ @@ -43,8 +43,6 @@ render_mode_create_options(const char *mode) { const char *parent = NULL; PyObject *base_options, *ret, *parent_options; unsigned int i, found_concrete; - if (render_mode_options == NULL) - return PyDict_New(); base_options = PyDict_GetItemString(render_mode_options, mode); if (base_options) { @@ -66,7 +64,7 @@ render_mode_create_options(const char *mode) { } /* check custom mode info if needed */ - if (found_concrete == 0 && custom_render_modes != NULL) { + if (found_concrete == 0) { PyObject *custom = PyDict_GetItemString(custom_render_modes, mode); if (custom) { custom = PyDict_GetItemString(custom, "parent"); @@ -106,8 +104,6 @@ render_mode_find_interface(const char *mode) { } /* check for custom modes */ - if (custom_render_modes == NULL) - return NULL; custom = PyDict_GetItemString(custom_render_modes, mode); if (custom == NULL) return NULL; @@ -236,13 +232,11 @@ PyObject *get_render_modes(PyObject *self, PyObject *args) { Py_DECREF(name); } - if (custom_render_modes != NULL) { - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { - PyList_Append(modes, key); - } + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { + PyList_Append(modes, key); } return modes; @@ -329,22 +323,20 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { } } - if (custom_render_modes != NULL) { - PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); - if (custom) { - PyObject *tmp, *copy = PyDict_Copy(custom); - Py_DECREF(info); - - tmp = PyString_FromString(rendermode); - PyDict_SetItemString(copy, "name", tmp); - Py_DECREF(tmp); - - tmp = PyList_New(0); - PyDict_SetItemString(copy, "options", tmp); - Py_DECREF(tmp); - - return copy; - } + PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + if (custom) { + PyObject *tmp, *copy = PyDict_Copy(custom); + Py_DECREF(info); + + tmp = PyString_FromString(rendermode); + PyDict_SetItemString(copy, "name", tmp); + Py_DECREF(tmp); + + tmp = PyList_New(0); + PyDict_SetItemString(copy, "options", tmp); + Py_DECREF(tmp); + + return copy; } Py_DECREF(info); @@ -365,17 +357,15 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { return NULL; /* take care of the chain of custom modes, if there are any */ - if (custom_render_modes != NULL) { - PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); - while (custom != NULL) { - PyObject *name = PyString_FromString(rendermode); - PyList_Append(parents, name); - Py_DECREF(name); - - custom = PyDict_GetItemString(custom, "parent"); - rendermode = PyString_AsString(custom); - custom = PyDict_GetItem(custom_render_modes, custom); - } + PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + while (custom != NULL) { + PyObject *name = PyString_FromString(rendermode); + PyList_Append(parents, name); + Py_DECREF(name); + + custom = PyDict_GetItemString(custom, "parent"); + rendermode = PyString_AsString(custom); + custom = PyDict_GetItem(custom_render_modes, custom); } /* now handle concrete modes */ @@ -423,17 +413,15 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { } } - if (custom_render_modes != NULL) { - PyObject *key, *value; - Py_ssize_t pos = 0; + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { + PyObject *pyparent = PyDict_GetItemString(value, "parent"); + const char *parent = PyString_AsString(pyparent); - while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { - PyObject *pyparent = PyDict_GetItemString(value, "parent"); - const char *parent = PyString_AsString(pyparent); - - if (strcmp(parent, rendermode) == 0) { - PyList_Append(children, key); - } + if (strcmp(parent, rendermode) == 0) { + PyList_Append(children, key); } } @@ -485,9 +473,6 @@ PyObject *set_render_mode_options(PyObject *self, PyObject *args) { } } - if (render_mode_options == NULL) - render_mode_options = PyDict_New(); - PyDict_SetItemString(render_mode_options, rendermode, opts); Py_RETURN_NONE; } @@ -498,9 +483,6 @@ PyObject *add_custom_render_mode(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts)) return NULL; - if (custom_render_modes == NULL) - custom_render_modes = PyDict_New(); - /* first, make sure the parent is set correctly */ pyparent = PyDict_GetItemString(opts, "parent"); if (pyparent == NULL) From 9516704057fbd74740f581a7492d27112bf94de3 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 19 Jul 2011 15:04:49 -0400 Subject: [PATCH 23/29] Fixed MSVC build errors --- overviewer_core/src/rendermodes.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index 075fb27..98c0df3 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -219,6 +219,9 @@ int render_mode_parse_option(PyObject *dict, const char *name, const char *forma PyObject *get_render_modes(PyObject *self, PyObject *args) { PyObject *modes; unsigned int i; + PyObject *key, *value; + Py_ssize_t pos = 0; + if (!PyArg_ParseTuple(args, "")) return NULL; @@ -232,8 +235,6 @@ PyObject *get_render_modes(PyObject *self, PyObject *args) { Py_DECREF(name); } - PyObject *key, *value; - Py_ssize_t pos = 0; while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { PyList_Append(modes, key); @@ -290,6 +291,8 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { const char* rendermode; PyObject *info; unsigned int i; + PyObject *custom; + if (!PyArg_ParseTuple(args, "s", &rendermode)) return NULL; @@ -323,7 +326,7 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { } } - PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + custom = PyDict_GetItemString(custom_render_modes, rendermode); if (custom) { PyObject *tmp, *copy = PyDict_Copy(custom); Py_DECREF(info); @@ -349,6 +352,8 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { PyObject *parents; unsigned int i; RenderModeInterface *iface = NULL; + PyObject *custom; + if (!PyArg_ParseTuple(args, "s", &rendermode)) return NULL; @@ -357,7 +362,7 @@ PyObject *get_render_mode_inheritance(PyObject *self, PyObject *args) { return NULL; /* take care of the chain of custom modes, if there are any */ - PyObject *custom = PyDict_GetItemString(custom_render_modes, rendermode); + custom = PyDict_GetItemString(custom_render_modes, rendermode); while (custom != NULL) { PyObject *name = PyString_FromString(rendermode); PyList_Append(parents, name); @@ -398,6 +403,9 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { const char *rendermode; PyObject *children; unsigned int i; + PyObject *key, *value; + Py_ssize_t pos = 0; + if (!PyArg_ParseTuple(args, "s", &rendermode)) return NULL; @@ -413,8 +421,6 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) { } } - PyObject *key, *value; - Py_ssize_t pos = 0; while (PyDict_Next(custom_render_modes, &pos, &key, &value)) { PyObject *pyparent = PyDict_GetItemString(value, "parent"); From 74d935686d22e7bfb333e792bb048d207aca8a36 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 5 Aug 2011 16:40:48 -0400 Subject: [PATCH 24/29] changed --list-rendermodes to be tree-based --- overviewer.py | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/overviewer.py b/overviewer.py index 638a82c..ed72afb 100755 --- a/overviewer.py +++ b/overviewer.py @@ -144,14 +144,7 @@ def main(): c_overviewer.set_render_mode_options(mode, options.rendermode_options[mode]) if options.list_rendermodes: - avail_rendermodes = c_overviewer.get_render_modes() - rendermode_info = map(c_overviewer.get_render_mode_info, avail_rendermodes) - name_width = max(map(lambda i: len(i['name']), rendermode_info)) - for info in rendermode_info: - if not 'description' in info: - print "{name:{0}} (no description)".format(name_width, **info) - else: - print "{name:{0}} {description}".format(name_width, **info) + list_rendermodes() sys.exit(0) if len(args) < 1: @@ -294,6 +287,47 @@ def delete_all(worlddir, tiledir): os.unlink(datfile) logging.info("Deleting {0}".format(datfile)) +def list_rendermodes(): + "Prints out a pretty list of supported rendermodes" + + def print_mode_tree(line_max, mode, prefix='', last=False): + "Prints out a mode tree for the given mode, with an indent." + + try: + info = c_overviewer.get_render_mode_info(mode) + except ValueError: + info = {} + + print prefix + '+-', mode, + + if 'description' in info: + print " " * (line_max - len(prefix) - len(mode) - 2), + print info['description'] + else: + print + + children = c_overviewer.get_render_mode_children(mode) + for child in children: + child_last = (child == children[-1]) + if last: + child_prefix = ' ' + else: + child_prefix = '| ' + print_mode_tree(line_max, child, prefix=prefix + child_prefix, last=child_last) + + avail_rendermodes = c_overviewer.get_render_modes() + line_lengths = {} + parent_modes = [] + for mode in avail_rendermodes: + inherit = c_overviewer.get_render_mode_inheritance(mode) + if not inherit[0] in parent_modes: + parent_modes.append(inherit[0]) + line_lengths[mode] = 2 * len(inherit) + 1 + len(mode) + + line_length = max(line_lengths.values()) + for mode in parent_modes: + print_mode_tree(line_length, mode, last=(mode == parent_modes[-1])) + def list_worlds(): "Prints out a brief summary of saves found in the default directory" print From 1594fc5465d5852451c95557e0a1f8e328fc6791 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 26 Aug 2011 21:05:12 -0400 Subject: [PATCH 25/29] fixed mistake on last merge that caused custom modes to be ignored --- overviewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index b2f440b..47bf66f 100755 --- a/overviewer.py +++ b/overviewer.py @@ -104,7 +104,7 @@ def main(): parser.add_option("-z", "--zoom", dest="zoom", helptext="Sets the zoom level manually instead of calculating it. This can be useful if you have outlier chunks that make your world too big. This value will make the highest zoom level contain (2**ZOOM)^2 tiles", action="store", type="int", advanced=True) parser.add_option("--regionlist", dest="regionlist", helptext="A file containing, on each line, a path to a regionlist to update. Instead of scanning the world directory for regions, it will just use this list. Normal caching rules still apply.") parser.add_option("--forcerender", dest="forcerender", helptext="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting it.", action="store_true") - parser.add_option("--rendermodes", dest="rendermode", helptext="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", choices=avail_rendermodes, required=True, default=avail_rendermodes[0], listify=True) + parser.add_option("--rendermodes", dest="rendermode", helptext="Specifies the render types, separated by commas. Use --list-rendermodes to list them all.", type="choice", required=True, default=avail_rendermodes[0], listify=True) parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", helptext="List available render modes and exit.", commandLineOnly=True) parser.add_option("--rendermode-options", dest="rendermode_options", default={}, advanced=True) parser.add_option("--custom-rendermodes", dest="custom_rendermodes", default={}, advanced=True) From bc138ac859a558bc2e7af82232721884c04324b9 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 7 Sep 2011 17:16:43 -0400 Subject: [PATCH 26/29] created a distinct 'hidden' function --- overviewer_core/src/iterate.c | 2 +- overviewer_core/src/rendermode-cave.c | 121 ++++++++++++---------- overviewer_core/src/rendermode-lighting.c | 11 +- overviewer_core/src/rendermode-mineral.c | 7 ++ overviewer_core/src/rendermode-night.c | 7 ++ overviewer_core/src/rendermode-normal.c | 23 ++-- overviewer_core/src/rendermode-overlay.c | 10 ++ overviewer_core/src/rendermode-spawn.c | 7 ++ overviewer_core/src/rendermodes.c | 4 + overviewer_core/src/rendermodes.h | 21 +++- 10 files changed, 145 insertions(+), 68 deletions(-) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 8ad2691..6fd58bf 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -376,7 +376,7 @@ chunk_render(PyObject *self, PyObject *args) { /* get blockid */ state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z); - if (state.block == 0) { + if (state.block == 0 || render_mode_hidden(rendermode, state.x, state.y, state.z)) { continue; } diff --git a/overviewer_core/src/rendermode-cave.c b/overviewer_core/src/rendermode-cave.c index e68578f..0b87377 100644 --- a/overviewer_core/src/rendermode-cave.c +++ b/overviewer_core/src/rendermode-cave.c @@ -80,13 +80,69 @@ touches_light(unsigned int x, unsigned int y, unsigned int z, } static int -rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { +rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { + /* first, check to see if it's "normally" occluded */ + if (rendermode_lighting.occluded(data, state, x, y, z)) + return 1; + + /* check for normal occlusion */ + /* use ajacent chunks, if not you get blocks spreaded in chunk edges */ + if ( (x == 0) && (y != 15) ) { + if (state->left_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y == 15) ) { + if (state->right_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x == 0) && (y == 15) ) { + if ((state->left_blocks != Py_None) && + (state->right_blocks != Py_None)) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y != 15) && + !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + + /* guess we're not occluded */ + return 0; +} + +static int +rendermode_cave_hidden(void *data, RenderState *state, int x, int y, int z) { RenderModeCave* self; int dz = 0; self = (RenderModeCave *)data; - /* first, check to see if it's "normally" occluded */ - if (rendermode_lighting.occluded(data, state, x, y, z)) + /* first, check to see if it's "normally" hidden */ + if (rendermode_lighting.hidden(data, state, x, y, z)) return 1; /* check if the block is touching skylight */ @@ -99,61 +155,14 @@ rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { if (self->only_lit && !touches_light(x, y, z, self->blocklight, self->left_blocklight, self->right_blocklight, self->up_left_blocklight, self->up_right_blocklight)) { return 1; } - - /* check for normal occlusion */ - /* use ajacent chunks, if not you get blocks spreaded in chunk edges */ - if ( (x == 0) && (y != 15) ) { - if (state->left_blocks != Py_None) { - if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && - !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x != 0) && (y == 15) ) { - if (state->right_blocks != Py_None) { - if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && - !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x == 0) && (y == 15) ) { - if ((state->left_blocks != Py_None) && - (state->right_blocks != Py_None)) { - if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && - !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x != 0) && (y != 15) && - !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && - !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { - return 1; - } - } else { /* if z == 127 skip */ return 1; } - /* check for lakes and seas and don't render them */ - /* at this point of the code the block has no skylight - * and is not occluded, but a deep sea can fool these - * 2 tests */ + /* check for lakes and seas and don't render them + * at this point of the code the block has no skylight + * but a deep sea can be completely dark + */ if ((getArrayByte3D(state->blocks, x, y, z) == 9) || (getArrayByte3D(state->blocks, x, y, z+1) == 9)) { @@ -169,8 +178,7 @@ rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { } } } - - + return 0; } @@ -284,5 +292,6 @@ RenderModeInterface rendermode_cave = { rendermode_cave_start, rendermode_cave_finish, rendermode_cave_occluded, + rendermode_cave_hidden, rendermode_cave_draw, }; diff --git a/overviewer_core/src/rendermode-lighting.c b/overviewer_core/src/rendermode-lighting.c index 20ef874..9897d6e 100644 --- a/overviewer_core/src/rendermode-lighting.c +++ b/overviewer_core/src/rendermode-lighting.c @@ -212,14 +212,12 @@ static inline void do_shading_with_mask(RenderModeLighting *self, RenderState *state, int x, int y, int z, PyObject *mask) { float black_coeff; - PyObject *blocks; /* first, check for occlusion if the block is in the local chunk */ if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) { unsigned char block = getArrayByte3D(state->blocks, x, y, z); - int occluded = render_mode_occluded(state->rendermode, x, y, z); - if (!occluded && !is_transparent(block)) { + if (!is_transparent(block) && !render_mode_hidden(state->rendermode, x, y, z)) { /* this face isn't visible, so don't draw anything */ return; } @@ -306,6 +304,12 @@ rendermode_lighting_occluded(void *data, RenderState *state, int x, int y, int z return rendermode_normal.occluded(data, state, x, y, z); } +static int +rendermode_lighting_hidden(void *data, RenderState *state, int x, int y, int z) { + /* no special hiding here */ + return rendermode_normal.hidden(data, state, x, y, z); +} + static void rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { RenderModeLighting* self; @@ -356,5 +360,6 @@ RenderModeInterface rendermode_lighting = { rendermode_lighting_start, rendermode_lighting_finish, rendermode_lighting_occluded, + rendermode_lighting_hidden, rendermode_lighting_draw, }; diff --git a/overviewer_core/src/rendermode-mineral.c b/overviewer_core/src/rendermode-mineral.c index 3a74d5a..e3887b9 100644 --- a/overviewer_core/src/rendermode-mineral.c +++ b/overviewer_core/src/rendermode-mineral.c @@ -136,6 +136,12 @@ rendermode_mineral_occluded(void *data, RenderState *state, int x, int y, int z) return rendermode_overlay.occluded(data, state, x, y, z); } +static int +rendermode_mineral_hidden(void *data, RenderState *state, int x, int y, int z) { + /* no special hiding here */ + return rendermode_overlay.hidden(data, state, x, y, z); +} + static void rendermode_mineral_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { /* draw normally */ @@ -155,5 +161,6 @@ RenderModeInterface rendermode_mineral = { rendermode_mineral_start, rendermode_mineral_finish, rendermode_mineral_occluded, + rendermode_mineral_hidden, rendermode_mineral_draw, }; diff --git a/overviewer_core/src/rendermode-night.c b/overviewer_core/src/rendermode-night.c index f1d38bd..32281a6 100644 --- a/overviewer_core/src/rendermode-night.c +++ b/overviewer_core/src/rendermode-night.c @@ -53,6 +53,12 @@ rendermode_night_occluded(void *data, RenderState *state, int x, int y, int z) { return rendermode_lighting.occluded(data, state, x, y, z); } +static int +rendermode_night_hidden(void *data, RenderState *state, int x, int y, int z) { + /* no special hiding here */ + return rendermode_lighting.hidden(data, state, x, y, z); +} + static void rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { /* nothing special to do */ @@ -67,5 +73,6 @@ RenderModeInterface rendermode_night = { rendermode_night_start, rendermode_night_finish, rendermode_night_occluded, + rendermode_night_hidden, rendermode_night_draw, }; diff --git a/overviewer_core/src/rendermode-normal.c b/overviewer_core/src/rendermode-normal.c index 547fb8c..5c0ac4f 100644 --- a/overviewer_core/src/rendermode-normal.c +++ b/overviewer_core/src/rendermode-normal.c @@ -135,13 +135,10 @@ rendermode_normal_finish(void *data, RenderState *state) { static int rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) { - RenderModeNormal *self = (RenderModeNormal *)data; - - if (z > self->max_depth || z < self->min_depth) { - return 1; - } - - if ( (x != 0) && (y != 15) && (z != self->max_depth) && + if ( (x != 0) && (y != 15) && (z != 127) && + !render_mode_hidden(state->rendermode, x-1, y, z) && + !render_mode_hidden(state->rendermode, x, y, z+1) && + !render_mode_hidden(state->rendermode, x, y+1, z) && !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { @@ -151,6 +148,17 @@ rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) return 0; } +static int +rendermode_normal_hidden(void *data, RenderState *state, int x, int y, int z) { + RenderModeNormal *self = (RenderModeNormal *)data; + + if (z > self->max_depth || z < self->min_depth) { + return 1; + } + + return 0; +} + static void rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { RenderModeNormal *self = (RenderModeNormal *)data; @@ -298,5 +306,6 @@ RenderModeInterface rendermode_normal = { rendermode_normal_start, rendermode_normal_finish, rendermode_normal_occluded, + rendermode_normal_hidden, rendermode_normal_draw, }; diff --git a/overviewer_core/src/rendermode-overlay.c b/overviewer_core/src/rendermode-overlay.c index 769c445..b909e33 100644 --- a/overviewer_core/src/rendermode-overlay.c +++ b/overviewer_core/src/rendermode-overlay.c @@ -59,6 +59,9 @@ rendermode_overlay_finish(void *data, RenderState *state) { static int rendermode_overlay_occluded(void *data, RenderState *state, int x, int y, int z) { if ( (x != 0) && (y != 15) && (z != 127) && + !render_mode_hidden(state->rendermode, x-1, y, z) && + !render_mode_hidden(state->rendermode, x, y, z+1) && + !render_mode_hidden(state->rendermode, x, y+1, z) && !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { @@ -68,6 +71,12 @@ rendermode_overlay_occluded(void *data, RenderState *state, int x, int y, int z) return 0; } +static int +rendermode_overlay_hidden(void *data, RenderState *state, int x, int y, int z) { + /* overlays hide nothing by default */ + return 0; +} + static void rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { RenderModeOverlay *self = (RenderModeOverlay *)data; @@ -132,5 +141,6 @@ RenderModeInterface rendermode_overlay = { rendermode_overlay_start, rendermode_overlay_finish, rendermode_overlay_occluded, + rendermode_overlay_hidden, rendermode_overlay_draw, }; diff --git a/overviewer_core/src/rendermode-spawn.c b/overviewer_core/src/rendermode-spawn.c index b812444..ffd478e 100644 --- a/overviewer_core/src/rendermode-spawn.c +++ b/overviewer_core/src/rendermode-spawn.c @@ -101,6 +101,12 @@ rendermode_spawn_occluded(void *data, RenderState *state, int x, int y, int z) { return rendermode_overlay.occluded(data, state, x, y, z); } +static int +rendermode_spawn_hidden(void *data, RenderState *state, int x, int y, int z) { + /* no special hiding here */ + return rendermode_overlay.hidden(data, state, x, y, z); +} + static void rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { /* draw normally */ @@ -115,5 +121,6 @@ RenderModeInterface rendermode_spawn = { rendermode_spawn_start, rendermode_spawn_finish, rendermode_spawn_occluded, + rendermode_spawn_hidden, rendermode_spawn_draw, }; diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index 98c0df3..45ff887 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -167,6 +167,10 @@ int render_mode_occluded(RenderMode *self, int x, int y, int z) { return self->iface->occluded(self->mode, self->state, x, y, z); } +int render_mode_hidden(RenderMode *self, int x, int y, int z) { + return self->iface->hidden(self->mode, self->state, x, y, z); +} + void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light) { self->iface->draw(self->mode, self->state, img, mask, mask_light); } diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h index 52473f3..ab257e2 100644 --- a/overviewer_core/src/rendermodes.h +++ b/overviewer_core/src/rendermodes.h @@ -62,12 +62,30 @@ struct _RenderModeInterface { /* may return non-zero on error, last arg is options */ int (*start)(void *, RenderState *, PyObject *); void (*finish)(void *, RenderState *); - /* returns non-zero to skip rendering this block */ + /* returns non-zero to skip rendering this block because it's not visible */ int (*occluded)(void *, RenderState *, int, int, int); + /* returns non-zero to skip rendering this block because the user doesn't + * want it visible */ + int (*hidden)(void *, RenderState *, int, int, int); /* last two arguments are img and mask, from texture lookup */ void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *); }; +/* A quick note about the difference between occluded and hidden: + * + * Occluded should be used to tell the renderer that a block will not be + * visible in the final image because other blocks will be drawn on top of + * it. This is a potentially *expensive* check that should be used rarely, + * usually only once per block. The idea is this check is expensive, but not + * as expensive as drawing the block itself. + * + * Hidden is used to tell the renderer not to draw the block, usually because + * the current rendermode depends on those blocks being hidden to do its + * job. For example, cave mode uses this to hide non-cave blocks. This check + * should be *cheap*, as it's potentially called many times per block. For + * example, in lighting mode it is called at most 4 times per block. + */ + /* wrapper for passing around rendermodes */ struct _RenderMode { void *mode; @@ -79,6 +97,7 @@ struct _RenderMode { RenderMode *render_mode_create(const char *mode, RenderState *state); void render_mode_destroy(RenderMode *self); int render_mode_occluded(RenderMode *self, int x, int y, int z); +int render_mode_hidden(RenderMode *self, int x, int y, int z); void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light); /* helper function for reading in rendermode options From bbb2a3943e7fd9a005f172ea71704e95f705116c Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 8 Sep 2011 07:07:43 -0400 Subject: [PATCH 27/29] re-fixed cave mode lighting problems (no longer slows down lighting mode itself!) --- overviewer_core/src/rendermode-cave.c | 125 ++++++++++++++-------- overviewer_core/src/rendermode-lighting.c | 7 +- overviewer_core/src/rendermodes.h | 5 + 3 files changed, 88 insertions(+), 49 deletions(-) diff --git a/overviewer_core/src/rendermode-cave.c b/overviewer_core/src/rendermode-cave.c index 0b87377..61469cd 100644 --- a/overviewer_core/src/rendermode-cave.c +++ b/overviewer_core/src/rendermode-cave.c @@ -79,6 +79,59 @@ touches_light(unsigned int x, unsigned int y, unsigned int z, return 0; } +static inline int +rendermode_cave_adjacent_occluded(void *data, RenderState *state, int x, int y, int z) { + /* check for occlusion of edge blocks, using adjacent block data */ + + if (z != 127) { + if ( (x == 0) && (y != 15) ) { + if (state->left_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y == 15) ) { + if (state->right_blocks != Py_None) { + if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x == 0) && (y == 15) ) { + if ((state->left_blocks != Py_None) && + (state->right_blocks != Py_None)) { + if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && + !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { + return 1; + } + } else { + return 1; + } + } + + if ( (x != 0) && (y != 15) && + !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + } + + return 0; +} + static int rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { /* first, check to see if it's "normally" occluded */ @@ -87,52 +140,7 @@ rendermode_cave_occluded(void *data, RenderState *state, int x, int y, int z) { /* check for normal occlusion */ /* use ajacent chunks, if not you get blocks spreaded in chunk edges */ - if ( (x == 0) && (y != 15) ) { - if (state->left_blocks != Py_None) { - if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && - !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x != 0) && (y == 15) ) { - if (state->right_blocks != Py_None) { - if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && - !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x == 0) && (y == 15) ) { - if ((state->left_blocks != Py_None) && - (state->right_blocks != Py_None)) { - if (!is_transparent(getArrayByte3D(state->left_blocks, 15, y, z)) && - !is_transparent(getArrayByte3D(state->right_blocks, x, 0, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1))) { - return 1; - } - } else { - return 1; - } - } - - if ( (x != 0) && (y != 15) && - !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && - !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && - !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { - return 1; - } - - /* guess we're not occluded */ - return 0; + return rendermode_cave_adjacent_occluded(data, state, x, y, z); } static int @@ -179,6 +187,23 @@ rendermode_cave_hidden(void *data, RenderState *state, int x, int y, int z) { } } + /* unfortunate side-effect of lit cave mode: we need to count occluded + * blocks as hidden for the lighting to look right, since technically our + * hiding depends on occlusion as well + * + * We leave out this check otherwise because it's fairly expensive. + */ + if (self->lighting) { + if ( (x != 0) && (y != 15) && (z != 127) && + !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) && + !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) && + !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) { + return 1; + } + + return rendermode_cave_adjacent_occluded(data, state, x, y, z); + } + return 0; } @@ -204,7 +229,13 @@ rendermode_cave_start(void *data, RenderState *state, PyObject *options) { self->lighting = 0; if (!render_mode_parse_option(options, "lighting", "i", &(self->lighting))) return 1; - + + if (self->lighting) + { + /* we can't skip lighting the sides in cave mode, it looks too weird */ + self->parent.skip_sides = 0; + } + /* if there's skylight we are in the surface! */ self->skylight = PyObject_GetAttrString(state->self, "skylight"); self->left_skylight = PyObject_GetAttrString(state->self, "left_skylight"); diff --git a/overviewer_core/src/rendermode-lighting.c b/overviewer_core/src/rendermode-lighting.c index 9897d6e..7fa6c24 100644 --- a/overviewer_core/src/rendermode-lighting.c +++ b/overviewer_core/src/rendermode-lighting.c @@ -221,7 +221,7 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state, /* this face isn't visible, so don't draw anything */ return; } - } else if ((x == -1) && (state->left_blocks != Py_None)) { + } else if (self->skip_sides && (x == -1) && (state->left_blocks != Py_None)) { unsigned char block = getArrayByte3D(state->left_blocks, 15, state->y, state->z); if (!is_transparent(block)) { /* the same thing but for adjacent chunks, this solves an @@ -230,7 +230,7 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state, tessellate-able */ return; } - } else if ((y == 16) && (state->right_blocks != Py_None)) { + } else if (self->skip_sides && (y == 16) && (state->right_blocks != Py_None)) { unsigned char block = getArrayByte3D(state->right_blocks, state->x, 0, state->z); if (!is_transparent(block)) { /* the same thing but for adjacent chunks, this solves an @@ -256,6 +256,9 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) { return ret; self = (RenderModeLighting *)data; + + /* skip sides by default */ + self->skip_sides = 1; self->shade_strength = 1.0; if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength))) diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h index ab257e2..a59fe0b 100644 --- a/overviewer_core/src/rendermodes.h +++ b/overviewer_core/src/rendermodes.h @@ -170,6 +170,11 @@ typedef struct { arguments are skylight, blocklight */ float (*calculate_darkness)(unsigned char, unsigned char); + /* can be set to 0 in derived modes to indicate that lighting the chunk + * sides is actually important. Right now, this is used in cave mode + */ + int skip_sides; + float shade_strength; } RenderModeLighting; extern RenderModeInterface rendermode_lighting; From fb45fb3dfffe59fb06a65e99c826e398f66d204a Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 8 Sep 2011 07:34:35 -0400 Subject: [PATCH 28/29] added label metadata to rendermodes (no more ugly map labels) --- overviewer_core/googlemap.py | 11 +++++++++-- overviewer_core/src/rendermode-cave.c | 3 ++- overviewer_core/src/rendermode-lighting.c | 3 ++- overviewer_core/src/rendermode-mineral.c | 3 ++- overviewer_core/src/rendermode-night.c | 3 ++- overviewer_core/src/rendermode-normal.c | 3 ++- overviewer_core/src/rendermode-overlay.c | 3 ++- overviewer_core/src/rendermode-spawn.c | 3 ++- overviewer_core/src/rendermodes.c | 4 ++++ overviewer_core/src/rendermodes.h | 2 ++ 10 files changed, 29 insertions(+), 9 deletions(-) diff --git a/overviewer_core/googlemap.py b/overviewer_core/googlemap.py index 50ff422..b30fa05 100644 --- a/overviewer_core/googlemap.py +++ b/overviewer_core/googlemap.py @@ -23,7 +23,7 @@ from time import strftime, localtime import json import util -from c_overviewer import get_render_mode_inheritance +from c_overviewer import get_render_mode_inheritance, get_render_mode_info import overviewer_version """ @@ -130,8 +130,15 @@ class MapGen(object): #config = config.replace("{bg_color}", self.bg_color) + # helper function to get a label for the given rendermode + def get_render_mode_label(rendermode): + info = get_render_mode_info(rendermode) + if 'label' in info: + return info['label'] + return rendermode.capitalize() + # create generated map type data, from given quadtrees - maptypedata = map(lambda q: {'label' : q.rendermode.capitalize(), + maptypedata = map(lambda q: {'label' : get_render_mode_label(q.rendermode), 'path' : q.tiledir, 'bg_color': self.bg_color, 'overlay' : 'overlay' in get_render_mode_inheritance(q.rendermode), diff --git a/overviewer_core/src/rendermode-cave.c b/overviewer_core/src/rendermode-cave.c index 61469cd..5e3336c 100644 --- a/overviewer_core/src/rendermode-cave.c +++ b/overviewer_core/src/rendermode-cave.c @@ -316,7 +316,8 @@ const RenderModeOption rendermode_cave_options[] = { }; RenderModeInterface rendermode_cave = { - "cave", "render only caves", + "cave", "Cave", + "render only caves", rendermode_cave_options, &rendermode_lighting, sizeof(RenderModeCave), diff --git a/overviewer_core/src/rendermode-lighting.c b/overviewer_core/src/rendermode-lighting.c index 7fa6c24..1774e1a 100644 --- a/overviewer_core/src/rendermode-lighting.c +++ b/overviewer_core/src/rendermode-lighting.c @@ -356,7 +356,8 @@ const RenderModeOption rendermode_lighting_options[] = { }; RenderModeInterface rendermode_lighting = { - "lighting", "draw shadows from the lighting data", + "lighting", "Lighting", + "draw shadows from the lighting data", rendermode_lighting_options, &rendermode_normal, sizeof(RenderModeLighting), diff --git a/overviewer_core/src/rendermode-mineral.c b/overviewer_core/src/rendermode-mineral.c index e3887b9..858333b 100644 --- a/overviewer_core/src/rendermode-mineral.c +++ b/overviewer_core/src/rendermode-mineral.c @@ -154,7 +154,8 @@ const RenderModeOption rendermode_mineral_options[] = { }; RenderModeInterface rendermode_mineral = { - "mineral", "draws a colored overlay showing where ores are located", + "mineral", "Mineral", + "draws a colored overlay showing where ores are located", rendermode_mineral_options, &rendermode_overlay, sizeof(RenderModeMineral), diff --git a/overviewer_core/src/rendermode-night.c b/overviewer_core/src/rendermode-night.c index 32281a6..6e08aaf 100644 --- a/overviewer_core/src/rendermode-night.c +++ b/overviewer_core/src/rendermode-night.c @@ -66,7 +66,8 @@ rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *m } RenderModeInterface rendermode_night = { - "night", "like \"lighting\", except at night", + "night", "Night", + "like \"lighting\", except at night", NULL, &rendermode_lighting, sizeof(RenderModeNight), diff --git a/overviewer_core/src/rendermode-normal.c b/overviewer_core/src/rendermode-normal.c index 5c0ac4f..d85a298 100644 --- a/overviewer_core/src/rendermode-normal.c +++ b/overviewer_core/src/rendermode-normal.c @@ -299,7 +299,8 @@ const RenderModeOption rendermode_normal_options[] = { }; RenderModeInterface rendermode_normal = { - "normal", "nothing special, just render the blocks", + "normal", "Normal", + "nothing special, just render the blocks", rendermode_normal_options, NULL, sizeof(RenderModeNormal), diff --git a/overviewer_core/src/rendermode-overlay.c b/overviewer_core/src/rendermode-overlay.c index b909e33..17b760b 100644 --- a/overviewer_core/src/rendermode-overlay.c +++ b/overviewer_core/src/rendermode-overlay.c @@ -134,7 +134,8 @@ rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject } RenderModeInterface rendermode_overlay = { - "overlay", "base rendermode for informational overlays", + "overlay", "Overlay", + "base rendermode for informational overlays", NULL, NULL, sizeof(RenderModeOverlay), diff --git a/overviewer_core/src/rendermode-spawn.c b/overviewer_core/src/rendermode-spawn.c index ffd478e..a5c0a27 100644 --- a/overviewer_core/src/rendermode-spawn.c +++ b/overviewer_core/src/rendermode-spawn.c @@ -114,7 +114,8 @@ rendermode_spawn_draw(void *data, RenderState *state, PyObject *src, PyObject *m } RenderModeInterface rendermode_spawn = { - "spawn", "draws a red overlay where monsters can spawn at night", + "spawn", "Spawn", + "draws a red overlay where monsters can spawn at night", NULL, &rendermode_overlay, sizeof(RenderModeSpawn), diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index 45ff887..ff7858d 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -312,6 +312,10 @@ PyObject *get_render_mode_info(PyObject *self, PyObject *args) { PyDict_SetItemString(info, "name", tmp); Py_DECREF(tmp); + tmp = PyString_FromString(render_modes[i]->label); + PyDict_SetItemString(info, "label", tmp); + Py_DECREF(tmp); + tmp = PyString_FromString(render_modes[i]->description); PyDict_SetItemString(info, "description", tmp); Py_DECREF(tmp); diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h index a59fe0b..310bf0e 100644 --- a/overviewer_core/src/rendermodes.h +++ b/overviewer_core/src/rendermodes.h @@ -48,6 +48,8 @@ typedef struct _RenderModeInterface RenderModeInterface; struct _RenderModeInterface { /* the name of this mode */ const char *name; + /* the label to use in the map */ + const char *label; /* the short description of this render mode */ const char *description; From e67dd9ba6ef3e7ad98077d5a4585f1a8318d6a8b Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 8 Sep 2011 07:49:09 -0400 Subject: [PATCH 29/29] incremented extension version for RMO --- overviewer_core/src/overviewer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index efe63b9..934dae8 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 10 +#define OVERVIEWER_EXTENSION_VERSION 11 /* Python PIL, and numpy headers */ #include