diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py
index 739e085..4b7fa7c 100644
--- a/overviewer_core/rendermodes.py
+++ b/overviewer_core/rendermodes.py
@@ -93,34 +93,45 @@ class DepthTinting(RenderPrimitive):
self._depth_colors = depth_colors
return depth_colors
-# Render 3 blending masks for lighting
-# first is top (+Z), second is left (-X), third is right (+Y)
-def generate_facemasks():
- white = Image.new("L", (24,24), 255)
+class Lighting(RenderPrimitive):
+ name = "lighting"
+ options = {
+ "strength": ("how dark to make the shadows, from 0.0 to 1.0", 1.0),
+ "night": ("whether to use nighttime skylight settings", False),
+ "color": ("whether to use colored light", False),
+ }
+
+ @property
+ def facemasks(self):
+ facemasks = getattr(self, "_facemasks", None)
+ if facemasks:
+ return facemasks
+
+ white = Image.new("L", (24,24), 255)
+
+ top = Image.new("L", (24,24), 0)
+ left = Image.new("L", (24,24), 0)
+ whole = Image.new("L", (24,24), 0)
+
+ toppart = textures.Textures.transform_image_top(white)
+ leftpart = textures.Textures.transform_image_side(white)
+
+ # using the real PIL paste here (not alpha_over) because there is
+ # no alpha channel (and it's mode "L")
+ top.paste(toppart, (0,0))
+ left.paste(leftpart, (0,6))
+ right = left.transpose(Image.FLIP_LEFT_RIGHT)
+
+ # Manually touch up 6 pixels that leave a gap, like in
+ # textures._build_block()
+ for x,y in [(13,23), (17,21), (21,19)]:
+ right.putpixel((x,y), 255)
+ for x,y in [(3,4), (7,2), (11,0)]:
+ top.putpixel((x,y), 255)
- top = Image.new("L", (24,24), 0)
- left = Image.new("L", (24,24), 0)
- whole = Image.new("L", (24,24), 0)
-
- toppart = textures.Textures.transform_image_top(white)
- leftpart = textures.Textures.transform_image_side(white)
-
- # using the real PIL paste here (not alpha_over) because there is
- # no alpha channel (and it's mode "L")
- top.paste(toppart, (0,0))
- left.paste(leftpart, (0,6))
- right = left.transpose(Image.FLIP_LEFT_RIGHT)
-
- # Manually touch up 6 pixels that leave a gap, like in
- # textures._build_block()
- for x,y in [(13,23), (17,21), (21,19)]:
- right.putpixel((x,y), 255)
- 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()
+ # special fix for chunk boundary stipple
+ for x,y in [(13,11), (17,9), (21,7)]:
+ right.putpixel((x,y), 0)
+
+ self._facemasks = (top, left, right)
+ return self._facemasks
diff --git a/overviewer_core/src/rendermode-lighting.c b/overviewer_core/src/primitives/lighting.c
similarity index 83%
rename from overviewer_core/src/rendermode-lighting.c
rename to overviewer_core/src/primitives/lighting.c
index a6eca00..a2d357f 100644
--- a/overviewer_core/src/rendermode-lighting.c
+++ b/overviewer_core/src/primitives/lighting.c
@@ -15,9 +15,37 @@
* with the Overviewer. If not, see .
*/
-#include "overviewer.h"
+#include "../overviewer.h"
#include
+typedef struct {
+ PyObject *facemasks_py;
+ PyObject *facemasks[3];
+
+ /* extra data, loaded off the chunk class */
+ PyObject *skylight, *blocklight;
+ PyObject *left_skylight, *left_blocklight;
+ PyObject *right_skylight, *right_blocklight;
+ PyObject *up_left_skylight, *up_left_blocklight;
+ PyObject *up_right_skylight, *up_right_blocklight;
+
+ /* light color image, loaded if color_light is True */
+ PyObject *lightcolor;
+
+ /* can be overridden in derived rendermodes to control lighting
+ arguments are data, skylight, blocklight, return RGB */
+ void (*calculate_light_color)(void *, unsigned char, unsigned char, unsigned char *, 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 strength;
+ int color;
+ int night;
+} RenderPrimitiveLighting;
+
/* figures out the color from a given skylight and blocklight,
used in lighting calculations */
static void
@@ -35,7 +63,7 @@ static void
calculate_light_color_fancy(void *data,
unsigned char skylight, unsigned char blocklight,
unsigned char *r, unsigned char *g, unsigned char *b) {
- RenderModeLighting *mode = (RenderModeLighting *)(data);
+ RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
unsigned int index;
PyObject *color;
@@ -70,7 +98,7 @@ static void
calculate_light_color_fancy_night(void *data,
unsigned char skylight, unsigned char blocklight,
unsigned char *r, unsigned char *g, unsigned char *b) {
- RenderModeLighting *mode = (RenderModeLighting *)(data);
+ RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
unsigned int index;
PyObject *color;
@@ -95,7 +123,7 @@ calculate_light_color_fancy_night(void *data,
*/
inline unsigned char
-estimate_blocklevel(RenderModeLighting *self, RenderState *state,
+estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state,
int x, int y, int z, int *authoratative) {
/* placeholders for later data arrays, coordinates */
@@ -185,7 +213,7 @@ estimate_blocklevel(RenderModeLighting *self, RenderState *state,
}
inline void
-get_lighting_color(RenderModeLighting *self, RenderState *state,
+get_lighting_color(RenderPrimitiveLighting *self, RenderState *state,
int x, int y, int z,
unsigned char *r, unsigned char *g, unsigned char *b) {
@@ -273,7 +301,10 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
if (block == 10 || block == 11) {
/* lava blocks should always be lit! */
- return 0.0f;
+ *r = 255;
+ *g = 255;
+ *b = 255;
+ return;
}
self->calculate_light_color(self, MIN(skylevel, 15), MIN(blocklevel, 15), r, g, b);
@@ -281,7 +312,7 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
/* does per-face occlusion checking for do_shading_with_mask */
inline int
-rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z) {
+lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z) {
/* 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);
@@ -315,52 +346,41 @@ rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x,
/* shades the drawn block with the given facemask, based on the
lighting results from (x, y, z) */
static inline void
-do_shading_with_mask(RenderModeLighting *self, RenderState *state,
+do_shading_with_mask(RenderPrimitiveLighting *self, RenderState *state,
int x, int y, int z, PyObject *mask) {
unsigned char r, g, b;
- float comp_shade_strength;
+ float comp_strength;
/* check occlusion */
- if (rendermode_lighting_is_face_occluded(state, self->skip_sides, x, y, z))
+ if (lighting_is_face_occluded(state, self->skip_sides, x, y, z))
return;
get_lighting_color(self, state, x, y, z, &r, &g, &b);
- comp_shade_strength = 1.0 - self->shade_strength;
+ comp_strength = 1.0 - self->strength;
- r += (255 - r) * comp_shade_strength;
- g += (255 - g) * comp_shade_strength;
- b += (255 - b) * comp_shade_strength;
+ r += (255 - r) * comp_strength;
+ g += (255 - g) * comp_strength;
+ b += (255 - b) * comp_strength;
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
}
static int
-rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
- RenderModeLighting* self;
-
- /* first, chain up */
- int ret = rendermode_normal.start(data, state, options);
- if (ret != 0)
- return ret;
+lighting_start(void *data, RenderState *state, PyObject *support) {
+ RenderPrimitiveLighting* self;
+ self = (RenderPrimitiveLighting *)data;
- self = (RenderModeLighting *)data;
-
- /* skip sides by default */
- self->skip_sides = 1;
+ /* don't skip sides by default */
+ self->skip_sides = 0;
- self->shade_strength = 1.0;
- if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength)))
+ if (!render_mode_parse_option(support, "strength", "f", &(self->strength)))
return 1;
-
- self->night = 0;
- if (!render_mode_parse_option(options, "night", "i", &(self->night)))
+ if (!render_mode_parse_option(support, "night", "i", &(self->night)))
return 1;
-
- self->color_light = 0;
- if (!render_mode_parse_option(options, "color_light", "i", &(self->color_light)))
+ if (!render_mode_parse_option(support, "color", "i", &(self->color)))
return 1;
- self->facemasks_py = PyObject_GetAttrString(state->support, "facemasks");
+ self->facemasks_py = PyObject_GetAttrString(support, "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);
@@ -383,12 +403,12 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
self->calculate_light_color = calculate_light_color;
}
- if (self->color_light) {
- self->lightcolor = PyObject_CallMethod(state->textures, "loadLightColor", "");
+ if (self->color) {
+ self->lightcolor = PyObject_CallMethod(state->textures, "load_light_color", "");
if (self->lightcolor == Py_None) {
Py_DECREF(self->lightcolor);
self->lightcolor = NULL;
- self->color_light = 0;
+ self->color = 0;
} else {
if (self->night) {
self->calculate_light_color = calculate_light_color_fancy_night;
@@ -404,8 +424,8 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
}
static void
-rendermode_lighting_finish(void *data, RenderState *state) {
- RenderModeLighting *self = (RenderModeLighting *)data;
+lighting_finish(void *data, RenderState *state) {
+ RenderPrimitiveLighting *self = (RenderPrimitiveLighting *)data;
Py_DECREF(self->facemasks_py);
@@ -419,32 +439,14 @@ rendermode_lighting_finish(void *data, RenderState *state) {
Py_DECREF(self->up_left_blocklight);
Py_DECREF(self->up_right_skylight);
Py_DECREF(self->up_right_blocklight);
-
- /* now chain up */
- rendermode_normal.finish(data, state);
-}
-
-static int
-rendermode_lighting_occluded(void *data, RenderState *state, int x, int y, int z) {
- /* no special occlusion here */
- return rendermode_normal.occluded(data, state, x, y, z);
-}
-
-static int
-rendermode_lighting_hidden(void *data, RenderState *state, int x, int y, int z) {
- /* no special hiding here */
- return rendermode_normal.hidden(data, state, x, y, z);
}
static void
-rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
- RenderModeLighting* self;
+lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
+ RenderPrimitiveLighting* self;
int x, y, z;
- /* first, chain up */
- rendermode_normal.draw(data, state, src, mask, mask_light);
-
- self = (RenderModeLighting *)data;
+ self = (RenderPrimitiveLighting *)data;
x = state->x, y = state->y, z = state->z;
if ((state->block == 9) || (state->block == 79)) { /* special case for water and ice */
@@ -473,22 +475,11 @@ 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)"},
- {"night", "whether to use nighttime skylight settings (default: False)"},
- {"color_light", "whether to use colored light (default: False)"},
- {NULL, NULL}
-};
-
-RenderModeInterface rendermode_lighting = {
- "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,
+RenderPrimitiveInterface primitive_lighting = {
+ "lighting", sizeof(RenderPrimitiveLighting),
+ lighting_start,
+ lighting_finish,
+ NULL,
+ NULL,
+ lighting_draw,
};
diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h
index 3d835ec..eb544ca 100644
--- a/overviewer_core/src/rendermodes.h
+++ b/overviewer_core/src/rendermodes.h
@@ -117,39 +117,6 @@ typedef struct {
} RenderModeOverlay;
extern RenderModeInterface rendermode_overlay;
-/* LIGHTING */
-typedef struct {
- /* inherits from normal render mode */
- RenderModeNormal parent;
-
- PyObject *facemasks_py;
- PyObject *facemasks[3];
-
- /* extra data, loaded off the chunk class */
- PyObject *skylight, *blocklight;
- PyObject *left_skylight, *left_blocklight;
- PyObject *right_skylight, *right_blocklight;
- PyObject *up_left_skylight, *up_left_blocklight;
- PyObject *up_right_skylight, *up_right_blocklight;
-
- /* light color image, loaded if color_light is True */
- PyObject *lightcolor;
-
- /* can be overridden in derived rendermodes to control lighting
- arguments are data, skylight, blocklight, return RGB */
- void (*calculate_light_color)(void *, unsigned char, unsigned char, unsigned char *, 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;
- int color_light;
- int night;
-} RenderModeLighting;
-extern RenderModeInterface rendermode_lighting;
-
/* exposed so it can be used in other per-face occlusion checks */
int rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z);
diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py
index d9b5739..4f628e2 100644
--- a/overviewer_core/textures.py
+++ b/overviewer_core/textures.py
@@ -56,8 +56,11 @@ class Textures(object):
def __getstate__(self):
# we must get rid of the huge image lists, and other images
attributes = self.__dict__.copy()
- for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture']:
- del attributes[attr]
+ for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture', 'lightcolor']:
+ try:
+ del attributes[attr]
+ except KeyError:
+ pass
return attributes
def __setstate__(self, attrs):
# regenerate textures, if needed
@@ -245,6 +248,18 @@ class Textures(object):
lavatexture = self.load_image("lava.png")
self.lavatexture = lavatexture
return lavatexture
+
+ def load_light_color(self):
+ """Helper function to load the light color texture."""
+ if hasattr(self, "lightcolor"):
+ return self.lightcolor
+ try:
+ lightcolor = list(_load_image("light_normal.png").getdata())
+ except Exception:
+ logging.warning("Light color image could not be found.")
+ lightcolor = None
+ self.lightcolor = lightcolor
+ return lightcolor
def _split_terrain(self, terrain):
"""Builds and returns a length 256 array of each 16x16 chunk
@@ -650,24 +665,6 @@ def getBiomeData(worlddir, chunkX, chunkY):
currentBiomeData = data
return data
-##
-## Color Light
-##
-
-lightcolor = None
-lightcolor_checked = False
-def loadLightColor():
- global lightcolor, lightcolor_checked
-
- if not lightcolor_checked:
- lightcolor_checked = True
- try:
- lightcolor = list(_load_image("light_normal.png").getdata())
- except Exception:
- logging.warning("Light color image could not be found.")
- lightcolor = None
- return lightcolor
-
##
## The other big one: @material and associated framework
##