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);