diff --git a/overviewer_core/__init__.py b/overviewer_core/__init__.py
index c3d3680..e69de29 100644
--- a/overviewer_core/__init__.py
+++ b/overviewer_core/__init__.py
@@ -1,7 +0,0 @@
-# c_overviewer must be imported first, because it imports other
-# modules; leaving this out can lead to bad dependency loops
-
-try:
- import c_overviewer
-except ImportError:
- pass
diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py
index e3386a3..0c988d2 100644
--- a/overviewer_core/rendermodes.py
+++ b/overviewer_core/rendermodes.py
@@ -16,6 +16,29 @@
from PIL import Image
import textures
+class RenderPrimitive(object):
+ options = {}
+ name = None
+ def __init__(self, **kwargs):
+ if self.name is None:
+ raise RuntimeError("RenderPrimitive cannot be used directly")
+
+ self.option_values = {}
+ for key, val in kwargs.iteritems():
+ if not key in self.options:
+ raise ValueError("primitive `{0}' has no option `{1}'".format(self.name, key))
+ self.option_values[key] = val
+
+class Base(RenderPrimitive):
+ 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)",
+ "nether": "if True, remove the roof of the map. Useful on nether maps. (defualt: False)",
+ }
+ name = "base"
+
# Render 3 blending masks for lighting
# first is top (+Z), second is left (-X), third is right (+Y)
def generate_facemasks():
diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c
index 22cfabd..f1e7bc2 100644
--- a/overviewer_core/src/iterate.c
+++ b/overviewer_core/src/iterate.c
@@ -18,7 +18,6 @@
#include "overviewer.h"
static PyObject *textures = NULL;
-static PyObject *support = NULL;
unsigned int max_blockid = 0;
unsigned int max_data = 0;
@@ -47,11 +46,6 @@ PyObject *init_chunk_render(void) {
return NULL;
}
- support = PyImport_ImportModule("overviewer_core.rendermodes");
- if (!support) {
- return NULL;
- }
-
tmp = PyObject_GetAttrString(textures, "max_blockid");
if (!tmp)
return NULL;
@@ -388,7 +382,7 @@ chunk_render(PyObject *self, PyObject *args) {
RenderState state;
PyObject *regionset;
int chunkx, chunkz;
- const char* rendermode_name = NULL;
+ PyObject *modeobj;
PyObject *blockmap;
int xoff, yoff;
@@ -406,14 +400,11 @@ chunk_render(PyObject *self, PyObject *args) {
PyObject *t = NULL;
- if (!PyArg_ParseTuple(args, "OiiOiisO", &state.regionset, &state.chunkx, &state.chunkz, &state.img, &xoff, &yoff, &rendermode_name, &state.textures))
+ if (!PyArg_ParseTuple(args, "OiiOiiOO", &state.regionset, &state.chunkx, &state.chunkz, &state.img, &xoff, &yoff, &modeobj, &state.textures))
return NULL;
- /* rendermode support */
- state.support = support;
-
/* set up the render mode */
- state.rendermode = rendermode = render_mode_create(rendermode_name, &state);
+ state.rendermode = rendermode = render_mode_create(modeobj, &state);
if (rendermode == NULL) {
return NULL; // note that render_mode_create will
// set PyErr. No need to set it here
diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h
index 1155724..517bb5b 100644
--- a/overviewer_core/src/overviewer.h
+++ b/overviewer_core/src/overviewer.h
@@ -79,9 +79,6 @@ typedef struct {
/* the Texture object */
PyObject *textures;
- /* the rendermode support module (rendermodes.py) */
- PyObject *support;
-
/* the block position and type, and the block array */
int x, y, z;
unsigned char block;
diff --git a/overviewer_core/src/rendermode-normal.c b/overviewer_core/src/primitives/base.c
similarity index 87%
rename from overviewer_core/src/rendermode-normal.c
rename to overviewer_core/src/primitives/base.c
index 39bc679..2ed70fc 100644
--- a/overviewer_core/src/rendermode-normal.c
+++ b/overviewer_core/src/primitives/base.c
@@ -15,33 +15,53 @@
* with the Overviewer. If not, see .
*/
-#include "overviewer.h"
+#include "../overviewer.h"
+
+typedef struct {
+ /* coordinates of the chunk, inside its region file */
+ int chunk_x, chunk_y;
+ /* biome data for the region */
+ PyObject *biome_data;
+ /* grasscolor and foliagecolor lookup tables */
+ PyObject *grasscolor, *foliagecolor, *watercolor;
+ /* biome-compatible grass/leaf textures */
+ PyObject *grass_texture;
+
+ /* 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;
+ int nether;
+} PrimitiveBase;
static int
-rendermode_normal_start(void *data, RenderState *state, PyObject *options) {
- RenderModeNormal *self = (RenderModeNormal *)data;
+base_start(void *data, RenderState *state, PyObject *support) {
+ PrimitiveBase *self = (PrimitiveBase *)data;
/* load up the given options, first */
self->edge_opacity = 0.15;
- if (!render_mode_parse_option(options, "edge_opacity", "f", &(self->edge_opacity)))
+ if (!render_mode_parse_option(support, "edge_opacity", "f", &(self->edge_opacity)))
return 1;
self->min_depth = 0;
- if (!render_mode_parse_option(options, "min_depth", "I", &(self->min_depth)))
+ if (!render_mode_parse_option(support, "min_depth", "I", &(self->min_depth)))
return 1;
self->max_depth = 127;
- if (!render_mode_parse_option(options, "max_depth", "I", &(self->max_depth)))
+ if (!render_mode_parse_option(support, "max_depth", "I", &(self->max_depth)))
return 1;
self->height_fading = 0;
/* XXX skip height fading */
- /*if (!render_mode_parse_option(options, "height_fading", "i", &(self->height_fading)))
+ /*if (!render_mode_parse_option(support, "height_fading", "i", &(self->height_fading)))
return 1;*/
self->nether = 0;
- if (!render_mode_parse_option(options, "nether", "i", &(self->nether)))
+ if (!render_mode_parse_option(support, "nether", "i", &(self->nether)))
return 1;
/*if (self->height_fading) {
@@ -95,8 +115,8 @@ rendermode_normal_start(void *data, RenderState *state, PyObject *options) {
}
static void
-rendermode_normal_finish(void *data, RenderState *state) {
- RenderModeNormal *self = (RenderModeNormal *)data;
+base_finish(void *data, RenderState *state) {
+ PrimitiveBase *self = (PrimitiveBase *)data;
Py_XDECREF(self->biome_data);
Py_XDECREF(self->foliagecolor);
@@ -108,7 +128,7 @@ rendermode_normal_finish(void *data, RenderState *state) {
}
static int
-rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) {
+base_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) &&
@@ -123,8 +143,8 @@ rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z)
}
static int
-rendermode_normal_hidden(void *data, RenderState *state, int x, int y, int z) {
- RenderModeNormal *self = (RenderModeNormal *)data;
+base_hidden(void *data, RenderState *state, int x, int y, int z) {
+ PrimitiveBase *self = (PrimitiveBase *)data;
if (z > self->max_depth || z < self->min_depth) {
return 1;
@@ -154,8 +174,8 @@ rendermode_normal_hidden(void *data, RenderState *state, int x, int y, int z) {
}
static void
-rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
- RenderModeNormal *self = (RenderModeNormal *)data;
+base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
+ PrimitiveBase *self = (PrimitiveBase *)data;
/* draw the block! */
alpha_over(state->img, src, mask, state->imgx, state->imgy, 0, 0);
@@ -360,24 +380,11 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
}
}
-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)"},
- {"nether", "if True, remove the roof of the map. Useful on nether maps. (default: False)"},
- {NULL, NULL}
-};
-
-RenderModeInterface rendermode_normal = {
- "normal", "Normal",
- "nothing special, just render the blocks",
- rendermode_normal_options,
- NULL,
- sizeof(RenderModeNormal),
- rendermode_normal_start,
- rendermode_normal_finish,
- rendermode_normal_occluded,
- rendermode_normal_hidden,
- rendermode_normal_draw,
+RenderPrimitiveInterface primitive_base = {
+ "base", sizeof(PrimitiveBase),
+ base_start,
+ base_finish,
+ base_occluded,
+ base_hidden,
+ base_draw,
};
diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c
index f26f629..fe69983 100644
--- a/overviewer_core/src/rendermodes.c
+++ b/overviewer_core/src/rendermodes.c
@@ -19,97 +19,166 @@
#include
#include
-/* list of all render modes, ending in NULL
- all of these will be available to the user, so DON'T include modes
- that are only useful as a base for other modes. */
-static RenderModeInterface *render_modes[] = {
- &rendermode_normal,
- &rendermode_lighting,
- &rendermode_smooth_lighting,
- &rendermode_cave,
+extern RenderPrimitiveInterface primitive_base;
+
+/* list of all render primitives, ending in NULL
+ all of these will be available to the user, so DON'T include primitives
+ that are only useful as a base for other primitives. */
+static RenderPrimitiveInterface *render_primitives[] = {
+ &primitive_base,
+ //&rendermode_lighting,
+ //&rendermode_smooth_lighting,
+ //&rendermode_cave,
- &rendermode_spawn,
- &rendermode_mineral,
+ //&rendermode_spawn,
+ //&rendermode_mineral,
NULL
};
/* rendermode encapsulation */
-RenderMode *render_mode_create(const char *mode, RenderState *state) {
- PyObject *options;
- RenderMode *ret = NULL;
- RenderModeInterface *iface = NULL;
+/* helper to create a single primitive */
+RenderPrimitive *render_primitive_create(PyObject *prim, RenderState *state) {
+ RenderPrimitive *ret = NULL;
+ RenderPrimitiveInterface *iface = NULL;
unsigned int i;
+ PyObject *pyname;
+ const char* name;
+
+ pyname = PyObject_GetAttrString(prim, "name");
+ if (!pyname)
+ return NULL;
+ name = PyString_AsString(pyname);
- for (i = 0; render_modes[i] != NULL; i++) {
- if (strcmp(render_modes[i]->name, mode) == 0) {
- iface = render_modes[i];
+ for (i = 0; render_primitives[i] != NULL; i++) {
+ if (strcmp(render_primitives[i]->name, name) == 0) {
+ iface = render_primitives[i];
break;
}
}
+ Py_DECREF(pyname);
if (iface == NULL)
return NULL;
- options = PyDict_New();
-
- ret = calloc(1, sizeof(RenderMode));
+ ret = calloc(1, sizeof(RenderPrimitive));
if (ret == NULL) {
- Py_DECREF(options);
- return PyErr_Format(PyExc_RuntimeError, "Failed to alloc a rendermode");
+ return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc a render primitive");
}
- ret->mode = calloc(1, iface->data_size);
- if (ret->mode == NULL) {
- Py_DECREF(options);
+ ret->primitive = calloc(1, iface->data_size);
+ if (ret->primitive == NULL) {
free(ret);
- return PyErr_Format(PyExc_RuntimeError, "Failed to alloc rendermode data");
+ return (RenderPrimitive *)PyErr_Format(PyExc_RuntimeError, "Failed to alloc render primitive data");
}
ret->iface = iface;
- ret->state = state;
- if (iface->start(ret->mode, state, options)) {
- Py_DECREF(options);
- free(ret->mode);
+ if (iface->start(ret->primitive, state, prim)) {
+ free(ret->primitive);
free(ret);
return NULL;
}
- Py_DECREF(options);
+ return ret;
+}
+
+RenderMode *render_mode_create(PyObject *mode, RenderState *state) {
+ RenderMode *ret = NULL;
+ PyObject *mode_fast = NULL;
+ unsigned int i;
+
+ mode_fast = PySequence_Fast(mode, "Mode is not a sequence type");
+ if (!mode_fast)
+ return NULL;
+
+ ret = calloc(1, sizeof(RenderMode));
+ ret->state = state;
+ ret->num_primitives = PySequence_Length(mode);
+ ret->primitives = calloc(ret->num_primitives, sizeof(RenderPrimitive*));
+ for (i = 0; i < ret->num_primitives; i++) {
+ PyObject *pyprim = PySequence_Fast_GET_ITEM(mode_fast, i);
+ RenderPrimitive *prim = render_primitive_create(pyprim, state);
+
+ if (!prim) {
+ render_mode_destroy(ret);
+ Py_DECREF(mode_fast);
+ return NULL;
+ }
+
+ ret->primitives[i] = prim;
+ }
+
return ret;
}
void render_mode_destroy(RenderMode *self) {
- self->iface->finish(self->mode, self->state);
- free(self->mode);
+ unsigned int i;
+
+ for (i = 0; i < self->num_primitives; i++) {
+ RenderPrimitive *prim = self->primitives[i];
+ /* we may be destroying a half-constructed mode, so we need this
+ check */
+ if (prim) {
+ prim->iface->finish(prim->primitive, self->state);
+ free(prim->primitive);
+ free(prim);
+ }
+ }
+ free(self->primitives);
free(self);
}
int render_mode_occluded(RenderMode *self, int x, int y, int z) {
- return self->iface->occluded(self->mode, self->state, x, y, z);
+ unsigned int i;
+ int occluded = 0;
+ for (i = 0; i < self->num_primitives; i++) {
+ RenderPrimitive *prim = self->primitives[i];
+ occluded |= prim->iface->occluded(prim->primitive, self->state, x, y, z);
+ if (occluded)
+ return occluded;
+ }
+ return occluded;
}
int render_mode_hidden(RenderMode *self, int x, int y, int z) {
- return self->iface->hidden(self->mode, self->state, x, y, z);
+ unsigned int i;
+ int hidden = 0;
+ for (i = 0; i < self->num_primitives; i++) {
+ RenderPrimitive *prim = self->primitives[i];
+ hidden |= prim->iface->hidden(prim->primitive, self->state, x, y, z);
+ if (hidden)
+ return hidden;
+ }
+ return hidden;
}
void render_mode_draw(RenderMode *self, PyObject *img, PyObject *mask, PyObject *mask_light) {
- self->iface->draw(self->mode, self->state, img, mask, mask_light);
+ unsigned int i;
+ for (i = 0; i < self->num_primitives; i++) {
+ RenderPrimitive *prim = self->primitives[i];
+ prim->iface->draw(prim->primitive, self->state, img, mask, mask_light);
+ }
}
/* options parse helper */
-int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...) {
+int render_mode_parse_option(PyObject *support, const char *name, const char *format, ...) {
va_list ap;
- PyObject *item;
+ PyObject *item, *dict;
int ret;
- if (dict == NULL || name == NULL)
+ if (support == NULL || name == NULL)
+ return 1;
+
+ dict = PyObject_GetAttrString(support, "option_values");
+ if (!dict)
return 1;
item = PyDict_GetItemString(dict, name);
- if (item == NULL)
+ if (item == NULL) {
+ Py_DECREF(dict);
return 1;
+ };
/* make sure the item we're parsing is a tuple
for VaParse to work correctly */
@@ -124,6 +193,7 @@ int render_mode_parse_option(PyObject *dict, const char *name, const char *forma
va_end(ap);
Py_DECREF(item);
+ Py_DECREF(dict);
if (!ret) {
PyObject *errtype, *errvalue, *errtraceback;
diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h
index 930f82e..add5bf9 100644
--- a/overviewer_core/src/rendermodes.h
+++ b/overviewer_core/src/rendermodes.h
@@ -16,20 +16,14 @@
*/
/*
- * To make a new render mode (the C part, at least):
+ * To make a new render primitive (the C part, at least):
*
* * add a data struct and extern'd interface declaration below
*
- * * fill in this interface struct in rendermode-(yourmode).c
- * (see rendermodes-normal.c for an example: the "normal" mode)
+ * * fill in this interface struct in primitives/(yourmode).c
+ * (see primitives/base.c for an example: the "base" primitive)
*
- * * if you want to derive from (say) the "normal" mode, put
- * a RenderModeNormal entry at the top of your data struct, and
- * be sure to call your parent's functions in your own!
- * (see rendermode-night.c for a simple example derived from
- * the "lighting" mode)
- *
- * * add your mode to the list in rendermodes.c
+ * * add your primitive to the list in rendermodes.c
*/
#ifndef __RENDERMODES_H_INCLUDED__
@@ -38,30 +32,14 @@
#include
#include "overviewer.h"
+/* render primitive interface */
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;
- /* the label to use in the map */
- const char *label;
- /* the short description of this render mode */
- 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;
+ const char *name;
/* the size of the local storage for this rendermode */
unsigned int data_size;
- /* may return non-zero on error, last arg is options */
+ /* may return non-zero on error, last arg is the python support object */
int (*start)(void *, RenderState *, PyObject *);
void (*finish)(void *, RenderState *);
/* returns non-zero to skip rendering this block because it's not visible */
@@ -71,7 +49,7 @@ struct _RenderModeInterface {
int (*hidden)(void *, RenderState *, int, int, int);
/* last two arguments are img and mask, from texture lookup */
void (*draw)(void *, RenderState *, PyObject *, PyObject *, PyObject *);
-};
+} RenderPrimitiveInterface;
/* A quick note about the difference between occluded and hidden:
*
@@ -88,47 +66,32 @@ struct _RenderModeInterface {
* example, in lighting mode it is called at most 4 times per block.
*/
+/* convenience wrapper for a single primitive + interface */
+typedef struct {
+ void *primitive;
+ RenderPrimitiveInterface *iface;
+} RenderPrimitive;
+
/* wrapper for passing around rendermodes */
struct _RenderMode {
- void *mode;
- RenderModeInterface *iface;
+ unsigned int num_primitives;
+ RenderPrimitive **primitives;
RenderState *state;
};
/* functions for creating / using rendermodes */
-RenderMode *render_mode_create(const char *mode, RenderState *state);
+RenderMode *render_mode_create(PyObject *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
- works like PyArg_ParseTuple on a dictionary item */
-int render_mode_parse_option(PyObject *dict, const char *name, const char *format, ...);
+ works like PyArg_ParseTuple on a support object */
+int render_mode_parse_option(PyObject *support, const char *name, const char *format, ...);
-/* individual rendermode interface declarations follow */
-
-/* NORMAL */
-typedef struct {
- /* coordinates of the chunk, inside its region file */
- int chunk_x, chunk_y;
- /* biome data for the region */
- PyObject *biome_data;
- /* grasscolor and foliagecolor lookup tables */
- PyObject *grasscolor, *foliagecolor, *watercolor;
- /* biome-compatible grass/leaf textures */
- PyObject *grass_texture;
-
- /* 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;
- int nether;
-} RenderModeNormal;
-extern RenderModeInterface rendermode_normal;
+/* XXX individual rendermode interface declarations follow */
+#ifdef OLD_MODES
/* OVERLAY */
typedef struct {
@@ -235,5 +198,6 @@ typedef struct {
void *minerals;
} RenderModeMineral;
extern RenderModeInterface rendermode_mineral;
+#endif /* OLD_MODES */
#endif /* __RENDERMODES_H_INCLUDED__ */
diff --git a/setup.py b/setup.py
index db2c3d9..ef01ea4 100755
--- a/setup.py
+++ b/setup.py
@@ -149,11 +149,12 @@ except Exception:
# used to figure out what files to compile
-render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave']
-render_modes += ['overlay', 'spawn', 'mineral']
+#render_modes = ['normal', 'lighting', 'smooth-lighting', 'cave']
+#render_modes += ['overlay', 'spawn', 'mineral']
+primitives = ['base',]
c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
-c_overviewer_files += map(lambda mode: 'rendermode-%s.c' % (mode,), render_modes)
+c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives)
c_overviewer_files += ['Draw.c']
c_overviewer_includes = ['overviewer.h', 'rendermodes.h']