From b312cef52ebaa6932cf3530f3cd527fdc251e5c6 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 21 Mar 2011 19:30:34 -0400 Subject: [PATCH] put lighting render mode in its own file; it's about to get *way* more complicated --- setup.py | 2 +- src/overviewer.h | 17 +----- src/rendermode-lighting.c | 114 ++++++++++++++++++++++++++++++++++++ src/rendermodes.c | 120 +------------------------------------- src/rendermodes.h | 76 ++++++++++++++++++++++++ 5 files changed, 194 insertions(+), 135 deletions(-) create mode 100644 src/rendermode-lighting.c create mode 100644 src/rendermodes.h diff --git a/setup.py b/setup.py index d918bd7..5777aa8 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ except AttributeError: numpy_include = numpy.get_numpy_include() -c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/rendermodes.c'] +c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/rendermodes.c', 'src/rendermode-lighting.c'] setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include], extra_link_args=["/MANIFEST"] if platform.system() == "Windows" else [])) # tell build_ext to build the extension in-place # (NOT in build/) diff --git a/src/overviewer.h b/src/overviewer.h index 4c6ec39..f85636e 100644 --- a/src/overviewer.h +++ b/src/overviewer.h @@ -63,20 +63,7 @@ int init_chunk_render(void); int is_transparent(unsigned char b); PyObject *chunk_render(PyObject *self, PyObject *args); -/* in rendermode.c */ -typedef struct { - /* the size of the local storage for this rendermode */ - unsigned int data_size; - - /* may return non-zero on error */ - int (*start)(void *, RenderState *); - void (*finish)(void *, RenderState *); - /* returns non-zero to skip rendering this block */ - int (*occluded)(void *, RenderState *); - /* last two arguments are img and mask, from texture lookup */ - void (*draw)(void *, RenderState *, PyObject *, PyObject *); -} RenderModeInterface; -/* figures out the render mode to use from the given ChunkRenderer */ -RenderModeInterface *get_render_mode(RenderState *state); +/* pull in the rendermode info */ +#include "rendermodes.h" #endif /* __OVERVIEWER_H_INCLUDED__ */ diff --git a/src/rendermode-lighting.c b/src/rendermode-lighting.c new file mode 100644 index 0000000..d6a123e --- /dev/null +++ b/src/rendermode-lighting.c @@ -0,0 +1,114 @@ +/* + * 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" + +/* shades the drawn block with the given facemask/black_color, based on the + lighting results from (x, y, z) */ +static inline void +do_shading_for_face(PyObject *chunk, int x, int y, int z, PyObject *facemask, PyObject *black_color, + PyObject *img, int imgx, int imgy) { + // returns new references + PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x, y, z); + PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0); + double black_coeff = PyFloat_AsDouble(black_coeff_py); + Py_DECREF(black_coeff_py); + + PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1); + int face_occlude = PyInt_AsLong(face_occlude_py); + Py_DECREF(face_occlude_py); + + + if (!face_occlude) { + //#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) + + PyObject *mask = PyObject_CallMethod(facemask, "copy", NULL); // new ref + //printf("black_coeff: %f\n", black_coeff); + brightness(mask, black_coeff); + //printf("done with brightness\n"); + alpha_over(img, black_color, mask, imgx, imgy, 0, 0); + //printf("done with alpha_over\n"); + Py_DECREF(mask); + + } +} + +static int +rendermode_lighting_start(void *data, RenderState *state) { + /* first, chain up */ + int ret = rendermode_normal.start(data, state); + if (ret != 0) + return ret; + + RenderModeLighting* self = (RenderModeLighting *)data; + + self->black_color = PyObject_GetAttrString(state->chunk, "black_color"); + self->facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks"); + // borrowed references, don't need to be decref'd + self->facemasks[0] = PyTuple_GetItem(self->facemasks_py, 0); + self->facemasks[1] = PyTuple_GetItem(self->facemasks_py, 1); + self->facemasks[2] = PyTuple_GetItem(self->facemasks_py, 2); + + return 0; +} + +static void +rendermode_lighting_finish(void *data, RenderState *state) { + RenderModeLighting *self = (RenderModeLighting *)data; + + Py_DECREF(self->black_color); + Py_DECREF(self->facemasks_py); + + /* now chain up */ + rendermode_normal.finish(data, state); +} + +static int +rendermode_lighting_occluded(void *data, RenderState *state) { + /* no special occlusion here */ + return rendermode_normal.occluded(data, state); +} + +static void +rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { + /* first, chain up */ + rendermode_normal.draw(data, state, src, mask); + + RenderModeLighting* self = (RenderModeLighting *)data; + + PyObject *chunk = state->self; + int x = state->x, y = state->y, z = state->z; + PyObject **facemasks = self->facemasks; + PyObject *black_color = self->black_color, *img = state->img; + int imgx = state->imgx, imgy = state->imgy; + + // FIXME whole-block shading for transparent blocks + do_shading_for_face(chunk, x, y, z+1, facemasks[0], black_color, + img, imgx, imgy); + do_shading_for_face(chunk, x-1, y, z, facemasks[1], black_color, + img, imgx, imgy); + do_shading_for_face(chunk, x, y+1, z, facemasks[2], black_color, + img, imgx, imgy); +} + +RenderModeInterface rendermode_lighting = { + sizeof(RenderModeLighting), + rendermode_lighting_start, + rendermode_lighting_finish, + rendermode_lighting_occluded, + rendermode_lighting_draw, +}; diff --git a/src/rendermodes.c b/src/rendermodes.c index d90968a..c4675e5 100644 --- a/src/rendermodes.c +++ b/src/rendermodes.c @@ -17,18 +17,6 @@ #include "overviewer.h" -/* - * ======================== - * == NORMAL rendermode === - * ======================== - */ - -typedef struct { - /* normal mode does not have any special data, so just use a dummy int - this way, normal mode is just like any other type of render mode */ - int dummy; -} RenderModeNormal; - static int rendermode_normal_start(void *data, RenderState *state) { /* do nothing */ @@ -67,114 +55,8 @@ RenderModeInterface rendermode_normal = { rendermode_normal_draw, }; -/* - * =========================== - * === LIGHTING rendermode === - * =========================== - */ - -typedef struct { - /* inherits from normal render mode */ - RenderModeNormal parent; - - PyObject *black_color, *facemasks_py; - PyObject *facemasks[3]; -} RenderModeLighting; - -/* shades the drawn block with the given facemask/black_color, based on the - lighting results from (x, y, z) */ -static inline void -do_shading_for_face(PyObject *chunk, int x, int y, int z, PyObject *facemask, PyObject *black_color, - PyObject *img, int imgx, int imgy) { - // returns new references - PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x, y, z); - PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0); - double black_coeff = PyFloat_AsDouble(black_coeff_py); - Py_DECREF(black_coeff_py); - - PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1); - int face_occlude = PyInt_AsLong(face_occlude_py); - Py_DECREF(face_occlude_py); - - - if (!face_occlude) { - //#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) - - PyObject *mask = PyObject_CallMethod(facemask, "copy", NULL); // new ref - //printf("black_coeff: %f\n", black_coeff); - brightness(mask, black_coeff); - //printf("done with brightness\n"); - alpha_over(img, black_color, mask, imgx, imgy, 0, 0); - //printf("done with alpha_over\n"); - Py_DECREF(mask); - - } -} - -static int -rendermode_lighting_start(void *data, RenderState *state) { - /* first, chain up */ - int ret = rendermode_normal_start(data, state); - if (ret != 0) - return ret; - - RenderModeLighting* self = (RenderModeLighting *)data; - - self->black_color = PyObject_GetAttrString(state->chunk, "black_color"); - self->facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks"); - // borrowed references, don't need to be decref'd - self->facemasks[0] = PyTuple_GetItem(self->facemasks_py, 0); - self->facemasks[1] = PyTuple_GetItem(self->facemasks_py, 1); - self->facemasks[2] = PyTuple_GetItem(self->facemasks_py, 2); - - return 0; -} - -static void -rendermode_lighting_finish(void *data, RenderState *state) { - RenderModeLighting *self = (RenderModeLighting *)data; - - Py_DECREF(self->black_color); - Py_DECREF(self->facemasks_py); - - /* now chain up */ - rendermode_normal_finish(data, state); -} - -static void -rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) { - /* first, chain up */ - rendermode_normal_draw(data, state, src, mask); - - RenderModeLighting* self = (RenderModeLighting *)data; - - PyObject *chunk = state->self; - int x = state->x, y = state->y, z = state->z; - PyObject **facemasks = self->facemasks; - PyObject *black_color = self->black_color, *img = state->img; - int imgx = state->imgx, imgy = state->imgy; - - // FIXME whole-block shading for transparent blocks - do_shading_for_face(chunk, x, y, z+1, facemasks[0], black_color, - img, imgx, imgy); - do_shading_for_face(chunk, x-1, y, z, facemasks[1], black_color, - img, imgx, imgy); - do_shading_for_face(chunk, x, y+1, z, facemasks[2], black_color, - img, imgx, imgy); -} - -RenderModeInterface rendermode_lighting = { - sizeof(RenderModeLighting), - rendermode_lighting_start, - rendermode_lighting_finish, - /* no special occlusion for lighting */ - rendermode_normal_occluded, - rendermode_lighting_draw, -}; - /* putting it all together */ -RenderModeInterface *get_render_mode(RenderState *state) -{ +RenderModeInterface *get_render_mode(RenderState *state) { /* default: normal */ RenderModeInterface *iface = &rendermode_normal; PyObject *quadtree = PyObject_GetAttrString(state->self, "quadtree"); diff --git a/src/rendermodes.h b/src/rendermodes.h new file mode 100644 index 0000000..89f12f1 --- /dev/null +++ b/src/rendermodes.h @@ -0,0 +1,76 @@ +/* + * 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 . + */ + +/* + * To make a new render mode (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.c for an example: the "normal" mode) + * + * * 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-lighting.c for an example) + * + * * add a condition to get_render_mode() in rendermodes.c + */ + +#ifndef __RENDERMODES_H_INCLUDED__ +#define __RENDERMODES_H_INCLUDED__ + +#include + +/* rendermode interface */ +typedef struct { + /* the size of the local storage for this rendermode */ + unsigned int data_size; + + /* may return non-zero on error */ + int (*start)(void *, RenderState *); + void (*finish)(void *, RenderState *); + /* returns non-zero to skip rendering this block */ + int (*occluded)(void *, RenderState *); + /* last two arguments are img and mask, from texture lookup */ + void (*draw)(void *, RenderState *, PyObject *, PyObject *); +} RenderModeInterface; + +/* figures out the render mode to use from the given ChunkRenderer */ +RenderModeInterface *get_render_mode(RenderState *state); + +/* individual rendermode interface declarations follow */ + +/* NORMAL */ +typedef struct { + /* normal mode does not have any special data, so just use a dummy int + this way, normal mode is just like any other type of render mode */ + int dummy; +} RenderModeNormal; +extern RenderModeInterface rendermode_normal; + +/* LIGHTING */ +typedef struct { + /* inherits from normal render mode */ + RenderModeNormal parent; + + PyObject *black_color, *facemasks_py; + PyObject *facemasks[3]; +} RenderModeLighting; +extern RenderModeInterface rendermode_lighting; + +#endif /* __RENDERMODES_H_INCLUDED__ */