converted lighting mode into a primitive
This commit is contained in:
@@ -93,9 +93,20 @@ class DepthTinting(RenderPrimitive):
|
|||||||
self._depth_colors = depth_colors
|
self._depth_colors = depth_colors
|
||||||
return depth_colors
|
return depth_colors
|
||||||
|
|
||||||
# Render 3 blending masks for lighting
|
class Lighting(RenderPrimitive):
|
||||||
# first is top (+Z), second is left (-X), third is right (+Y)
|
name = "lighting"
|
||||||
def generate_facemasks():
|
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)
|
white = Image.new("L", (24,24), 255)
|
||||||
|
|
||||||
top = Image.new("L", (24,24), 0)
|
top = Image.new("L", (24,24), 0)
|
||||||
@@ -122,5 +133,5 @@ def generate_facemasks():
|
|||||||
for x,y in [(13,11), (17,9), (21,7)]:
|
for x,y in [(13,11), (17,9), (21,7)]:
|
||||||
right.putpixel((x,y), 0)
|
right.putpixel((x,y), 0)
|
||||||
|
|
||||||
return (top, left, right)
|
self._facemasks = (top, left, right)
|
||||||
facemasks = generate_facemasks()
|
return self._facemasks
|
||||||
|
|||||||
@@ -15,9 +15,37 @@
|
|||||||
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "overviewer.h"
|
#include "../overviewer.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
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,
|
/* figures out the color from a given skylight and blocklight,
|
||||||
used in lighting calculations */
|
used in lighting calculations */
|
||||||
static void
|
static void
|
||||||
@@ -35,7 +63,7 @@ static void
|
|||||||
calculate_light_color_fancy(void *data,
|
calculate_light_color_fancy(void *data,
|
||||||
unsigned char skylight, unsigned char blocklight,
|
unsigned char skylight, unsigned char blocklight,
|
||||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||||
RenderModeLighting *mode = (RenderModeLighting *)(data);
|
RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
PyObject *color;
|
PyObject *color;
|
||||||
|
|
||||||
@@ -70,7 +98,7 @@ static void
|
|||||||
calculate_light_color_fancy_night(void *data,
|
calculate_light_color_fancy_night(void *data,
|
||||||
unsigned char skylight, unsigned char blocklight,
|
unsigned char skylight, unsigned char blocklight,
|
||||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||||
RenderModeLighting *mode = (RenderModeLighting *)(data);
|
RenderPrimitiveLighting *mode = (RenderPrimitiveLighting *)(data);
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
PyObject *color;
|
PyObject *color;
|
||||||
|
|
||||||
@@ -95,7 +123,7 @@ calculate_light_color_fancy_night(void *data,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
inline unsigned char
|
inline unsigned char
|
||||||
estimate_blocklevel(RenderModeLighting *self, RenderState *state,
|
estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state,
|
||||||
int x, int y, int z, int *authoratative) {
|
int x, int y, int z, int *authoratative) {
|
||||||
|
|
||||||
/* placeholders for later data arrays, coordinates */
|
/* placeholders for later data arrays, coordinates */
|
||||||
@@ -185,7 +213,7 @@ estimate_blocklevel(RenderModeLighting *self, RenderState *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
get_lighting_color(RenderModeLighting *self, RenderState *state,
|
get_lighting_color(RenderPrimitiveLighting *self, RenderState *state,
|
||||||
int x, int y, int z,
|
int x, int y, int z,
|
||||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
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) {
|
if (block == 10 || block == 11) {
|
||||||
/* lava blocks should always be lit! */
|
/* 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);
|
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 */
|
/* does per-face occlusion checking for do_shading_with_mask */
|
||||||
inline int
|
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 */
|
/* 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) {
|
if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) {
|
||||||
unsigned char block = getArrayByte3D(state->blocks, x, y, z);
|
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
|
/* shades the drawn block with the given facemask, based on the
|
||||||
lighting results from (x, y, z) */
|
lighting results from (x, y, z) */
|
||||||
static inline void
|
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) {
|
int x, int y, int z, PyObject *mask) {
|
||||||
unsigned char r, g, b;
|
unsigned char r, g, b;
|
||||||
float comp_shade_strength;
|
float comp_strength;
|
||||||
|
|
||||||
/* check occlusion */
|
/* 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;
|
return;
|
||||||
|
|
||||||
get_lighting_color(self, state, x, y, z, &r, &g, &b);
|
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;
|
r += (255 - r) * comp_strength;
|
||||||
g += (255 - g) * comp_shade_strength;
|
g += (255 - g) * comp_strength;
|
||||||
b += (255 - b) * comp_shade_strength;
|
b += (255 - b) * comp_strength;
|
||||||
|
|
||||||
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
|
tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
lighting_start(void *data, RenderState *state, PyObject *support) {
|
||||||
RenderModeLighting* self;
|
RenderPrimitiveLighting* self;
|
||||||
|
self = (RenderPrimitiveLighting *)data;
|
||||||
|
|
||||||
/* first, chain up */
|
/* don't skip sides by default */
|
||||||
int ret = rendermode_normal.start(data, state, options);
|
self->skip_sides = 0;
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
self = (RenderModeLighting *)data;
|
if (!render_mode_parse_option(support, "strength", "f", &(self->strength)))
|
||||||
|
return 1;
|
||||||
/* skip sides by default */
|
if (!render_mode_parse_option(support, "night", "i", &(self->night)))
|
||||||
self->skip_sides = 1;
|
return 1;
|
||||||
|
if (!render_mode_parse_option(support, "color", "i", &(self->color)))
|
||||||
self->shade_strength = 1.0;
|
|
||||||
if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength)))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
self->night = 0;
|
self->facemasks_py = PyObject_GetAttrString(support, "facemasks");
|
||||||
if (!render_mode_parse_option(options, "night", "i", &(self->night)))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
self->color_light = 0;
|
|
||||||
if (!render_mode_parse_option(options, "color_light", "i", &(self->color_light)))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
self->facemasks_py = PyObject_GetAttrString(state->support, "facemasks");
|
|
||||||
// borrowed references, don't need to be decref'd
|
// borrowed references, don't need to be decref'd
|
||||||
self->facemasks[0] = PyTuple_GetItem(self->facemasks_py, 0);
|
self->facemasks[0] = PyTuple_GetItem(self->facemasks_py, 0);
|
||||||
self->facemasks[1] = PyTuple_GetItem(self->facemasks_py, 1);
|
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;
|
self->calculate_light_color = calculate_light_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->color_light) {
|
if (self->color) {
|
||||||
self->lightcolor = PyObject_CallMethod(state->textures, "loadLightColor", "");
|
self->lightcolor = PyObject_CallMethod(state->textures, "load_light_color", "");
|
||||||
if (self->lightcolor == Py_None) {
|
if (self->lightcolor == Py_None) {
|
||||||
Py_DECREF(self->lightcolor);
|
Py_DECREF(self->lightcolor);
|
||||||
self->lightcolor = NULL;
|
self->lightcolor = NULL;
|
||||||
self->color_light = 0;
|
self->color = 0;
|
||||||
} else {
|
} else {
|
||||||
if (self->night) {
|
if (self->night) {
|
||||||
self->calculate_light_color = calculate_light_color_fancy_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
|
static void
|
||||||
rendermode_lighting_finish(void *data, RenderState *state) {
|
lighting_finish(void *data, RenderState *state) {
|
||||||
RenderModeLighting *self = (RenderModeLighting *)data;
|
RenderPrimitiveLighting *self = (RenderPrimitiveLighting *)data;
|
||||||
|
|
||||||
Py_DECREF(self->facemasks_py);
|
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_left_blocklight);
|
||||||
Py_DECREF(self->up_right_skylight);
|
Py_DECREF(self->up_right_skylight);
|
||||||
Py_DECREF(self->up_right_blocklight);
|
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
|
static void
|
||||||
rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeLighting* self;
|
RenderPrimitiveLighting* self;
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
|
|
||||||
/* first, chain up */
|
self = (RenderPrimitiveLighting *)data;
|
||||||
rendermode_normal.draw(data, state, src, mask, mask_light);
|
|
||||||
|
|
||||||
self = (RenderModeLighting *)data;
|
|
||||||
x = state->x, y = state->y, z = state->z;
|
x = state->x, y = state->y, z = state->z;
|
||||||
|
|
||||||
if ((state->block == 9) || (state->block == 79)) { /* special case for water and ice */
|
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[] = {
|
RenderPrimitiveInterface primitive_lighting = {
|
||||||
{"shade_strength", "how dark to make the shadows, from 0.0 to 1.0 (default: 1.0)"},
|
"lighting", sizeof(RenderPrimitiveLighting),
|
||||||
{"night", "whether to use nighttime skylight settings (default: False)"},
|
lighting_start,
|
||||||
{"color_light", "whether to use colored light (default: False)"},
|
lighting_finish,
|
||||||
{NULL, NULL}
|
NULL,
|
||||||
};
|
NULL,
|
||||||
|
lighting_draw,
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
@@ -117,39 +117,6 @@ typedef struct {
|
|||||||
} RenderModeOverlay;
|
} RenderModeOverlay;
|
||||||
extern RenderModeInterface rendermode_overlay;
|
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 */
|
/* 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);
|
int rendermode_lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z);
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,11 @@ class Textures(object):
|
|||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
# we must get rid of the huge image lists, and other images
|
# we must get rid of the huge image lists, and other images
|
||||||
attributes = self.__dict__.copy()
|
attributes = self.__dict__.copy()
|
||||||
for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture']:
|
for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture', 'lightcolor']:
|
||||||
|
try:
|
||||||
del attributes[attr]
|
del attributes[attr]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
return attributes
|
return attributes
|
||||||
def __setstate__(self, attrs):
|
def __setstate__(self, attrs):
|
||||||
# regenerate textures, if needed
|
# regenerate textures, if needed
|
||||||
@@ -246,6 +249,18 @@ class Textures(object):
|
|||||||
self.lavatexture = lavatexture
|
self.lavatexture = lavatexture
|
||||||
return 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):
|
def _split_terrain(self, terrain):
|
||||||
"""Builds and returns a length 256 array of each 16x16 chunk
|
"""Builds and returns a length 256 array of each 16x16 chunk
|
||||||
of texture.
|
of texture.
|
||||||
@@ -650,24 +665,6 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
|||||||
currentBiomeData = data
|
currentBiomeData = data
|
||||||
return 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
|
## The other big one: @material and associated framework
|
||||||
##
|
##
|
||||||
|
|||||||
Reference in New Issue
Block a user