Merge branch 'rendermode-options'
This commit is contained in:
@@ -306,6 +306,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)
|
||||
@@ -333,6 +340,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 chunk_render(self, img=None, xoff=0, yoff=0, cave=False):
|
||||
"""Renders a chunk with the given parameters, and returns the image.
|
||||
If img is given, the chunk is rendered to that image object. Otherwise,
|
||||
@@ -413,6 +427,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))
|
||||
|
||||
@@ -191,7 +191,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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -69,6 +69,12 @@ def pool_initializer(rendernode):
|
||||
north_direction=rendernode.options.get('north_direction', None))
|
||||
c_overviewer.init_chunk_render()
|
||||
|
||||
# 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])
|
||||
|
||||
# load biome data in each process, if needed
|
||||
for quadtree in rendernode.quadtrees:
|
||||
if quadtree.world.useBiomeData:
|
||||
@@ -145,7 +151,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)
|
||||
|
||||
@@ -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("overviewer_core.textures");
|
||||
@@ -298,6 +297,7 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) {
|
||||
PyObject*
|
||||
chunk_render(PyObject *self, PyObject *args) {
|
||||
RenderState state;
|
||||
PyObject *rendermode_py;
|
||||
|
||||
int xoff, yoff;
|
||||
|
||||
@@ -310,10 +310,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))
|
||||
@@ -324,11 +322,11 @@ 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);
|
||||
return Py_BuildValue("i", "-1");
|
||||
rendermode_py = PyObject_GetAttrString(state.self, "rendermode");
|
||||
state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state);
|
||||
Py_DECREF(rendermode_py);
|
||||
if (rendermode == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the image size */
|
||||
@@ -378,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;
|
||||
}
|
||||
|
||||
@@ -398,7 +396,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, state.x, state.y, state.z)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -457,7 +455,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
||||
state.imgy += randy;
|
||||
}
|
||||
|
||||
rendermode->draw(rm_data, &state, src, mask, mask_light);
|
||||
render_mode_draw(rendermode, src, mask, mask_light);
|
||||
|
||||
if (state.block == 31) {
|
||||
/* undo the random offsets */
|
||||
@@ -475,8 +473,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);
|
||||
|
||||
@@ -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);
|
||||
@@ -35,13 +39,16 @@ 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"},
|
||||
|
||||
{"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"},
|
||||
|
||||
@@ -52,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();
|
||||
}
|
||||
|
||||
@@ -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 <Python.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 */
|
||||
|
||||
@@ -17,77 +17,73 @@
|
||||
|
||||
#include "overviewer.h"
|
||||
#include <math.h>
|
||||
//~
|
||||
//~ /* 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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* check if the block is touching skylight */
|
||||
if (z != 127) {
|
||||
|
||||
if (getArrayByte3D(self->skylight, x, y, z+1) != 0) {
|
||||
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 == 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) {
|
||||
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 (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) {
|
||||
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 (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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* check for normal occlusion */
|
||||
/* use ajacent chunks, if not you get blocks spreaded in chunk edges */
|
||||
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)) &&
|
||||
@@ -99,7 +95,7 @@ rendermode_cave_occluded(void *data, RenderState *state) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( (x != 0) && (y == 15) ) {
|
||||
if (state->right_blocks != Py_None) {
|
||||
if (!is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) &&
|
||||
@@ -111,7 +107,7 @@ rendermode_cave_occluded(void *data, RenderState *state) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( (x == 0) && (y == 15) ) {
|
||||
if ((state->left_blocks != Py_None) &&
|
||||
(state->right_blocks != Py_None)) {
|
||||
@@ -124,22 +120,57 @@ rendermode_cave_occluded(void *data, RenderState *state) {
|
||||
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))) {
|
||||
!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 */
|
||||
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 */
|
||||
return rendermode_cave_adjacent_occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
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" hidden */
|
||||
if (rendermode_lighting.hidden(data, state, x, y, z))
|
||||
return 1;
|
||||
|
||||
/* check if the block is touching skylight */
|
||||
if (z != 127) {
|
||||
|
||||
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 (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;
|
||||
}
|
||||
} 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)) {
|
||||
@@ -155,33 +186,74 @@ rendermode_cave_occluded(void *data, RenderState *state) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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_lighting.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
self->depth_tinting = 1;
|
||||
if (!render_mode_parse_option(options, "depth_tinting", "i", &(self->depth_tinting)))
|
||||
return 1;
|
||||
|
||||
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 (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");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -189,16 +261,24 @@ 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);
|
||||
rendermode_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -211,24 +291,39 @@ 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
RenderModeInterface rendermode_cave = {
|
||||
"cave", "render only caves in normal mode",
|
||||
&rendermode_normal,
|
||||
"cave", "Cave",
|
||||
"render only caves",
|
||||
rendermode_cave_options,
|
||||
&rendermode_lighting,
|
||||
sizeof(RenderModeCave),
|
||||
rendermode_cave_start,
|
||||
rendermode_cave_finish,
|
||||
rendermode_cave_occluded,
|
||||
rendermode_cave_hidden,
|
||||
rendermode_cave_draw,
|
||||
};
|
||||
|
||||
@@ -169,13 +169,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);
|
||||
}
|
||||
|
||||
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
|
||||
blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
|
||||
|
||||
@@ -219,15 +212,16 @@ static inline void
|
||||
do_shading_with_mask(RenderModeLighting *self, RenderState *state,
|
||||
int x, int y, int z, PyObject *mask) {
|
||||
float black_coeff;
|
||||
|
||||
|
||||
/* 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)) {
|
||||
|
||||
if (!is_transparent(block) && !render_mode_hidden(state->rendermode, x, y, z)) {
|
||||
/* 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
|
||||
@@ -236,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
|
||||
@@ -248,20 +242,28 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state,
|
||||
}
|
||||
|
||||
black_coeff = get_lighting_coefficient(self, state, x, y, z);
|
||||
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) {
|
||||
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;
|
||||
|
||||
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)))
|
||||
return 1;
|
||||
|
||||
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
|
||||
@@ -300,9 +302,15 @@ 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 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
|
||||
@@ -342,12 +350,20 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject
|
||||
}
|
||||
}
|
||||
|
||||
const 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 = {
|
||||
"lighting", "draw shadows from the lighting data",
|
||||
"lighting", "Lighting",
|
||||
"draw shadows from the lighting data",
|
||||
rendermode_lighting_options,
|
||||
&rendermode_normal,
|
||||
sizeof(RenderModeLighting),
|
||||
rendermode_lighting_start,
|
||||
rendermode_lighting_finish,
|
||||
rendermode_lighting_occluded,
|
||||
rendermode_lighting_hidden,
|
||||
rendermode_lighting_draw,
|
||||
};
|
||||
|
||||
167
overviewer_core/src/rendermode-mineral.c
Normal file
167
overviewer_core/src/rendermode-mineral.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
|
||||
struct MineralColor {
|
||||
unsigned char blockid;
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
/* put more valuable ores first -- they take precedence */
|
||||
static struct MineralColor default_minerals[] = {
|
||||
{48 /* Mossy Stone */, 31, 153, 9},
|
||||
|
||||
{56 /* Diamond Ore */, 32, 230, 220},
|
||||
|
||||
{21 /* Lapis Lazuli */, 0, 23, 176},
|
||||
{14 /* Gold Ore */, 255, 234, 0},
|
||||
|
||||
{15 /* Iron Ore */, 204, 204, 204},
|
||||
{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}
|
||||
};
|
||||
|
||||
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 + 1, z;
|
||||
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;
|
||||
unsigned char blockid = getArrayByte3D(state->blocks, x, y, z);
|
||||
|
||||
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);
|
||||
|
||||
max_i = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_mineral_start(void *data, RenderState *state, PyObject *options) {
|
||||
PyObject *opt;
|
||||
RenderModeMineral* self;
|
||||
|
||||
/* first, chain up */
|
||||
int ret = rendermode_overlay.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_mineral_finish(void *data, RenderState *state) {
|
||||
/* first free all *our* stuff */
|
||||
RenderModeMineral* self = (RenderModeMineral *)data;
|
||||
|
||||
if (self->minerals && self->minerals != default_minerals) {
|
||||
free(self->minerals);
|
||||
}
|
||||
|
||||
/* now, chain up */
|
||||
rendermode_overlay.finish(data, state);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_mineral_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special occlusion here */
|
||||
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 */
|
||||
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", "Mineral",
|
||||
"draws a colored overlay showing where ores are located",
|
||||
rendermode_mineral_options,
|
||||
&rendermode_overlay,
|
||||
sizeof(RenderModeMineral),
|
||||
rendermode_mineral_start,
|
||||
rendermode_mineral_finish,
|
||||
rendermode_mineral_occluded,
|
||||
rendermode_mineral_hidden,
|
||||
rendermode_mineral_draw,
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -48,9 +48,15 @@ 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 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
|
||||
@@ -60,11 +66,14 @@ 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),
|
||||
rendermode_night_start,
|
||||
rendermode_night_finish,
|
||||
rendermode_night_occluded,
|
||||
rendermode_night_hidden,
|
||||
rendermode_night_draw,
|
||||
};
|
||||
|
||||
@@ -18,10 +18,33 @@
|
||||
#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;
|
||||
|
||||
/* load up the given options, first */
|
||||
|
||||
self->edge_opacity = 0.15;
|
||||
if (!render_mode_parse_option(options, "edge_opacity", "f", &(self->edge_opacity)))
|
||||
return 1;
|
||||
|
||||
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;
|
||||
|
||||
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");
|
||||
|
||||
@@ -106,13 +129,16 @@ 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
|
||||
rendermode_normal_occluded(void *data, RenderState *state) {
|
||||
int x = state->x, y = state->y, z = state->z;
|
||||
|
||||
rendermode_normal_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))) {
|
||||
@@ -122,6 +148,17 @@ rendermode_normal_occluded(void *data, RenderState *state) {
|
||||
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;
|
||||
@@ -192,13 +229,27 @@ 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)
|
||||
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
|
||||
@@ -239,12 +290,23 @@ 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)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
RenderModeInterface rendermode_normal = {
|
||||
"normal", "nothing special, just render the blocks",
|
||||
"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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -57,10 +57,11 @@ 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) &&
|
||||
!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))) {
|
||||
@@ -70,6 +71,12 @@ rendermode_overlay_occluded(void *data, RenderState *state) {
|
||||
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;
|
||||
@@ -127,11 +134,14 @@ 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),
|
||||
rendermode_overlay_start,
|
||||
rendermode_overlay_finish,
|
||||
rendermode_overlay_occluded,
|
||||
rendermode_overlay_hidden,
|
||||
rendermode_overlay_draw,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -96,9 +96,15 @@ 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 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
|
||||
@@ -108,11 +114,14 @@ 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),
|
||||
rendermode_spawn_start,
|
||||
rendermode_spawn_finish,
|
||||
rendermode_spawn_occluded,
|
||||
rendermode_spawn_hidden,
|
||||
rendermode_spawn_draw,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "overviewer.h"
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* list of all render modes, ending in NULL
|
||||
all of these will be available to the user, so DON'T include modes
|
||||
@@ -27,32 +28,204 @@ static RenderModeInterface *render_modes[] = {
|
||||
&rendermode_night,
|
||||
&rendermode_spawn,
|
||||
&rendermode_cave,
|
||||
&rendermode_mineral,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* decides which render mode to use */
|
||||
RenderModeInterface *get_render_mode(RenderState *state) {
|
||||
unsigned int i;
|
||||
/* default: NULL --> an error */
|
||||
RenderModeInterface *iface = NULL;
|
||||
PyObject *rendermode_py = PyObject_GetAttrString(state->self, "rendermode");
|
||||
const char *rendermode = PyString_AsString(rendermode_py);
|
||||
PyObject *render_mode_options = NULL;
|
||||
PyObject *custom_render_modes = NULL;
|
||||
|
||||
/* rendermode encapsulation */
|
||||
|
||||
/* helper to recursively find options for a given mode */
|
||||
static inline PyObject *
|
||||
render_mode_create_options(const char *mode) {
|
||||
const char *parent = NULL;
|
||||
PyObject *base_options, *ret, *parent_options;
|
||||
unsigned int i, found_concrete;
|
||||
|
||||
base_options = PyDict_GetItemString(render_mode_options, mode);
|
||||
if (base_options) {
|
||||
ret = PyDict_Copy(base_options);
|
||||
} else {
|
||||
ret = PyDict_New();
|
||||
}
|
||||
|
||||
/* figure out the parent mode name */
|
||||
found_concrete = 0;
|
||||
for (i = 0; render_modes[i] != NULL; i++) {
|
||||
if (strcmp(render_modes[i]->name, rendermode) == 0) {
|
||||
iface = render_modes[i];
|
||||
if (strcmp(render_modes[i]->name, mode) == 0) {
|
||||
found_concrete = 1;
|
||||
if (render_modes[i]->parent) {
|
||||
parent = render_modes[i]->parent->name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(rendermode_py);
|
||||
return iface;
|
||||
/* check custom mode info if needed */
|
||||
if (found_concrete == 0) {
|
||||
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(ret);
|
||||
Py_DECREF(parent_options);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(parent_options);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
|
||||
iface = render_mode_find_interface(mode);
|
||||
if (iface == NULL)
|
||||
return NULL;
|
||||
|
||||
options = render_mode_create_options(mode);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = calloc(1, sizeof(RenderMode));
|
||||
if (ret == NULL) {
|
||||
Py_DECREF(options);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->mode = calloc(1, iface->data_size);
|
||||
if (ret->mode == NULL) {
|
||||
Py_DECREF(options);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->iface = iface;
|
||||
ret->state = state;
|
||||
|
||||
if (iface->start(ret->mode, state, options)) {
|
||||
Py_DECREF(options);
|
||||
free(ret->mode);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_DECREF(options);
|
||||
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, 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
unsigned int i;
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
@@ -66,14 +239,64 @@ PyObject *get_render_modes(PyObject *self, PyObject *args) {
|
||||
Py_DECREF(name);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
PyObject *info;
|
||||
unsigned int i;
|
||||
PyObject *custom;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &rendermode))
|
||||
return NULL;
|
||||
|
||||
@@ -89,37 +312,45 @@ 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -129,6 +360,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;
|
||||
|
||||
@@ -136,6 +369,19 @@ 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 */
|
||||
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];
|
||||
@@ -165,6 +411,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;
|
||||
|
||||
@@ -180,5 +429,119 @@ PyObject *get_render_mode_children(PyObject *self, PyObject *args) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
/* 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, *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
RenderModeInterface *iface = NULL;
|
||||
if (!PyArg_ParseTuple(args, "sO!", &rendermode, &PyDict_Type, &opts))
|
||||
return NULL;
|
||||
|
||||
iface = render_mode_find_interface(rendermode);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -36,38 +36,86 @@
|
||||
#define __RENDERMODES_H_INCLUDED__
|
||||
|
||||
#include <Python.h>
|
||||
#include "overviewer.h"
|
||||
|
||||
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 label to use in the map */
|
||||
const char *label;
|
||||
/* 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;
|
||||
/* 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 *);
|
||||
/* 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 *);
|
||||
};
|
||||
|
||||
/* figures out the render mode to use from the given ChunkRenderer */
|
||||
RenderModeInterface *get_render_mode(RenderState *state);
|
||||
/* python bindings */
|
||||
/* 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;
|
||||
RenderModeInterface *iface;
|
||||
RenderState *state;
|
||||
};
|
||||
|
||||
/* 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 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, ...);
|
||||
|
||||
/* 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);
|
||||
PyObject *add_custom_render_mode(PyObject *self, PyObject *args);
|
||||
|
||||
/* individual rendermode interface declarations follow */
|
||||
|
||||
/* NORMAL */
|
||||
@@ -82,6 +130,14 @@ typedef struct {
|
||||
PyObject *grass_texture, *leaf_texture, *tall_grass_texture, *tall_fern_texture;
|
||||
/* 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;
|
||||
|
||||
@@ -115,10 +171,15 @@ typedef struct {
|
||||
/* can be overridden in derived rendermodes to control lighting
|
||||
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;
|
||||
inline float get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
||||
int x, int y, int z);
|
||||
|
||||
/* NIGHT */
|
||||
typedef struct {
|
||||
@@ -141,7 +202,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;
|
||||
@@ -150,10 +211,29 @@ 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;
|
||||
int lighting;
|
||||
} RenderModeCave;
|
||||
extern RenderModeInterface rendermode_cave;
|
||||
|
||||
/* MINERAL */
|
||||
typedef struct {
|
||||
/* inherits from overlay */
|
||||
RenderModeOverlay parent;
|
||||
|
||||
void *minerals;
|
||||
} RenderModeMineral;
|
||||
extern RenderModeInterface rendermode_mineral;
|
||||
|
||||
#endif /* __RENDERMODES_H_INCLUDED__ */
|
||||
|
||||
Reference in New Issue
Block a user