Merge branch 'smooth-lighting'
This commit is contained in:
@@ -124,7 +124,11 @@ var overviewer = {
|
||||
for (i in overviewerConfig.mapTypes) {
|
||||
var view = overviewerConfig.mapTypes[i];
|
||||
var imageFormat = view.imgformat ? view.imgformat : 'png';
|
||||
mapOptions[view.label] = {
|
||||
|
||||
if (view.shortname == null)
|
||||
view.shortname = view.label.replace(/\s+/g, "");
|
||||
|
||||
mapOptions[view.shortname] = {
|
||||
'getTileUrl': overviewer.gmap.getTileUrlGenerator(view.path,
|
||||
view.base, imageFormat),
|
||||
'tileSize': new google.maps.Size(
|
||||
@@ -134,19 +138,20 @@ var overviewer = {
|
||||
'minZoom': overviewerConfig.map.minZoom,
|
||||
'isPng': imageFormat.toLowerCase() == 'png'
|
||||
}
|
||||
overviewer.collections.mapTypes[view.label] = new google.maps.ImageMapType(
|
||||
mapOptions[view.label]);
|
||||
overviewer.collections.mapTypes[view.label].name = view.label;
|
||||
overviewer.collections.mapTypes[view.label].alt = 'Minecraft ' +
|
||||
overviewer.collections.mapTypes[view.shortname] = new google.maps.ImageMapType(
|
||||
mapOptions[view.shortname]);
|
||||
overviewer.collections.mapTypes[view.shortname].name = view.label;
|
||||
overviewer.collections.mapTypes[view.shortname].shortname = view.shortname;
|
||||
overviewer.collections.mapTypes[view.shortname].alt = 'Minecraft ' +
|
||||
view.label + ' Map';
|
||||
overviewer.collections.mapTypes[view.label].projection =
|
||||
overviewer.collections.mapTypes[view.shortname].projection =
|
||||
new overviewer.classes.MapProjection();
|
||||
if (view.overlay) {
|
||||
overviewer.collections.overlays.push(
|
||||
overviewer.collections.mapTypes[view.label]);
|
||||
overviewer.collections.mapTypes[view.shortname]);
|
||||
} else {
|
||||
overviewer.collections.mapTypeIds.push(
|
||||
overviewerConfig.CONST.mapDivId + view.label);
|
||||
overviewerConfig.CONST.mapDivId + view.shortname);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -245,7 +250,7 @@ var overviewer = {
|
||||
// Now attach the coordinate map type to the map's registry
|
||||
for (i in overviewer.collections.mapTypes) {
|
||||
overviewer.map.mapTypes.set(overviewerConfig.CONST.mapDivId +
|
||||
overviewer.collections.mapTypes[i].name,
|
||||
overviewer.collections.mapTypes[i].shortname,
|
||||
overviewer.collections.mapTypes[i]);
|
||||
}
|
||||
|
||||
@@ -482,7 +487,7 @@ var overviewer = {
|
||||
'getMapTypeBackgroundColor': function(mapTypeId) {
|
||||
for(i in overviewerConfig.mapTypes) {
|
||||
if( overviewerConfig.CONST.mapDivId +
|
||||
overviewerConfig.mapTypes[i].label == mapTypeId ) {
|
||||
overviewerConfig.mapTypes[i].shortname == mapTypeId ) {
|
||||
overviewer.util.debug('Found background color for: ' +
|
||||
overviewerConfig.mapTypes[i].bg_color);
|
||||
return overviewerConfig.mapTypes[i].bg_color;
|
||||
@@ -974,6 +979,11 @@ var overviewer = {
|
||||
}
|
||||
},
|
||||
'setHash': function(x, y, z, zoom, maptype) {
|
||||
// remove the div prefix from the maptype (looks better)
|
||||
if (maptype)
|
||||
{
|
||||
maptype = maptype.replace(overviewerConfig.CONST.mapDivId, "");
|
||||
}
|
||||
window.location.replace("#/" + Math.floor(x) + "/" + Math.floor(y) + "/" + Math.floor(z) + "/" + zoom + "/" + maptype);
|
||||
},
|
||||
'updateHash': function() {
|
||||
@@ -1023,7 +1033,20 @@ var overviewer = {
|
||||
// We can now set the map to use the 'coordinate' map type
|
||||
overviewer.map.setMapTypeId(overviewer.util.getDefaultMapTypeId());
|
||||
} else {
|
||||
overviewer.map.setMapTypeId(maptype);
|
||||
// normalize the map type (this supports old-style,
|
||||
// 'mcmapLabel' style map types, converts them to 'shortname'
|
||||
if (maptype.lastIndexOf(overviewerConfig.CONST.mapDivId, 0) === 0) {
|
||||
maptype = maptype.replace(overviewerConfig.CONST.mapDivId, "");
|
||||
for (i in overviewer.collections.mapTypes) {
|
||||
var type = overviewer.collections.mapTypes[i];
|
||||
if (type.name == maptype) {
|
||||
maptype = type.shortname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
overviewer.map.setMapTypeId(overviewerConfig.CONST.mapDivId + maptype);
|
||||
}
|
||||
|
||||
overviewer.map.setCenter(latlngcoords);
|
||||
|
||||
@@ -172,6 +172,10 @@ var overviewerConfig = {
|
||||
* the js/html server.
|
||||
* imgformat : string. File extension used for these tiles. Defaults to png.
|
||||
* overlay : bool. If true, this tile set will be treated like an overlay
|
||||
* bg_color : string. A #RRGGBB format background color.
|
||||
* shortname : string. Used in the dynamic anchor link mechanism. If not
|
||||
* present, label is used instead.
|
||||
*
|
||||
* Example:
|
||||
* 'mapTypes': [
|
||||
* {'label': 'Day', 'path': 'lighting/tiles'},
|
||||
|
||||
@@ -139,6 +139,7 @@ class MapGen(object):
|
||||
|
||||
# create generated map type data, from given quadtrees
|
||||
maptypedata = map(lambda q: {'label' : get_render_mode_label(q.rendermode),
|
||||
'shortname' : q.rendermode,
|
||||
'path' : q.tiledir,
|
||||
'bg_color': self.bg_color,
|
||||
'overlay' : 'overlay' in get_render_mode_inheritance(q.rendermode),
|
||||
|
||||
@@ -358,3 +358,129 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg,
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* draws a triangle on the destination image, multiplicatively!
|
||||
* used for smooth lighting
|
||||
* (excuse the ridiculous number of parameters!)
|
||||
*
|
||||
* Algorithm adapted from _Fundamentals_of_Computer_Graphics_
|
||||
* by Peter Shirley, Michael Ashikhmin
|
||||
* (or at least, the version poorly reproduced here:
|
||||
* http://www.gidforums.com/t-20838.html )
|
||||
*/
|
||||
PyObject *
|
||||
draw_triangle(PyObject *dest, int inclusive,
|
||||
int x0, int y0,
|
||||
unsigned char r0, unsigned char g0, unsigned char b0,
|
||||
int x1, int y1,
|
||||
unsigned char r1, unsigned char g1, unsigned char b1,
|
||||
int x2, int y2,
|
||||
unsigned char r2, unsigned char g2, unsigned char b2,
|
||||
int tux, int tuy, int *touchups, unsigned int num_touchups) {
|
||||
|
||||
/* destination image */
|
||||
Imaging imDest;
|
||||
/* ranges of pixels that are affected */
|
||||
int xmin, xmax, ymin, ymax;
|
||||
/* constant coefficients for alpha, beta, gamma */
|
||||
int a12, a20, a01;
|
||||
int b12, b20, b01;
|
||||
int c12, c20, c01;
|
||||
/* constant normalizers for alpha, beta, gamma */
|
||||
float alpha_norm, beta_norm, gamma_norm;
|
||||
/* temporary variables */
|
||||
int tmp;
|
||||
/* iteration variables */
|
||||
int x, y;
|
||||
|
||||
imDest = imaging_python_to_c(dest);
|
||||
if (!imDest)
|
||||
return NULL;
|
||||
|
||||
/* check the various image modes, make sure they make sense */
|
||||
if (strcmp(imDest->mode, "RGBA") != 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"given destination image does not have mode \"RGBA\"");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set up draw ranges */
|
||||
xmin = MIN(x0, MIN(x1, x2));
|
||||
ymin = MIN(y0, MIN(y1, y2));
|
||||
xmax = MAX(x0, MAX(x1, x2)) + 1;
|
||||
ymax = MAX(y0, MAX(y1, y2)) + 1;
|
||||
|
||||
xmin = MAX(xmin, 0);
|
||||
ymin = MAX(ymin, 0);
|
||||
xmax = MIN(xmax, imDest->xsize);
|
||||
ymax = MIN(ymax, imDest->ysize);
|
||||
|
||||
/* setup coefficients */
|
||||
a12 = y1 - y2; b12 = x2 - x1; c12 = (x1 * y2) - (x2 * y1);
|
||||
a20 = y2 - y0; b20 = x0 - x2; c20 = (x2 * y0) - (x0 * y2);
|
||||
a01 = y0 - y1; b01 = x1 - x0; c01 = (x0 * y1) - (x1 * y0);
|
||||
|
||||
/* setup normalizers */
|
||||
alpha_norm = 1.0f / ((a12 * x0) + (b12 * y0) + c12);
|
||||
beta_norm = 1.0f / ((a20 * x1) + (b20 * y1) + c20);
|
||||
gamma_norm = 1.0f / ((a01 * x2) + (b01 * y2) + c01);
|
||||
|
||||
/* iterate over the destination rect */
|
||||
for (y = ymin; y < ymax; y++) {
|
||||
UINT8 *out = (UINT8 *)imDest->image[y] + xmin * 4;
|
||||
|
||||
for (x = xmin; x < xmax; x++) {
|
||||
float alpha, beta, gamma;
|
||||
alpha = alpha_norm * ((a12 * x) + (b12 * y) + c12);
|
||||
beta = beta_norm * ((a20 * x) + (b20 * y) + c20);
|
||||
gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01);
|
||||
|
||||
if (alpha >= 0 && beta >= 0 && gamma >= 0 &&
|
||||
(inclusive || (alpha * beta * gamma > 0))) {
|
||||
unsigned int r = alpha * r0 + beta * r1 + gamma * r2;
|
||||
unsigned int g = alpha * g0 + beta * g1 + gamma * g2;
|
||||
unsigned int b = alpha * b0 + beta * b1 + gamma * b2;
|
||||
|
||||
*out = MULDIV255(*out, r, tmp); out++;
|
||||
*out = MULDIV255(*out, g, tmp); out++;
|
||||
*out = MULDIV255(*out, b, tmp); out++;
|
||||
|
||||
/* keep alpha the same */
|
||||
out++;
|
||||
} else {
|
||||
/* skip */
|
||||
out += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (num_touchups > 0) {
|
||||
float alpha, beta, gamma;
|
||||
unsigned int r, g, b;
|
||||
UINT8 *out;
|
||||
|
||||
x = touchups[0] + tux;
|
||||
y = touchups[1] + tuy;
|
||||
touchups += 2;
|
||||
num_touchups--;
|
||||
|
||||
if (x < 0 || x >= imDest->xsize || y < 0 || y >= imDest->ysize)
|
||||
continue;
|
||||
|
||||
out = (UINT8 *)imDest->image[y] + x * 4;
|
||||
|
||||
alpha = alpha_norm * ((a12 * x) + (b12 * y) + c12);
|
||||
beta = beta_norm * ((a20 * x) + (b20 * y) + c20);
|
||||
gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01);
|
||||
|
||||
r = alpha * r0 + beta * r1 + gamma * r2;
|
||||
g = alpha * g0 + beta * g1 + gamma * g2;
|
||||
b = alpha * b0 + beta * b1 + gamma * b2;
|
||||
|
||||
*out = MULDIV255(*out, r, tmp); out++;
|
||||
*out = MULDIV255(*out, g, tmp); out++;
|
||||
*out = MULDIV255(*out, b, tmp); out++;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,14 @@ PyObject *alpha_over_wrap(PyObject *self, PyObject *args);
|
||||
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);
|
||||
PyObject *draw_triangle(PyObject *dest, int inclusive,
|
||||
int x0, int y0,
|
||||
unsigned char r0, unsigned char g0, unsigned char b0,
|
||||
int x1, int y1,
|
||||
unsigned char r1, unsigned char g1, unsigned char b1,
|
||||
int x2, int y2,
|
||||
unsigned char r2, unsigned char g2, unsigned char b2,
|
||||
int tux, int tuy, int *touchups, unsigned int num_touchups);
|
||||
|
||||
/* forward declaration of RenderMode object */
|
||||
typedef struct _RenderMode RenderMode;
|
||||
|
||||
@@ -51,6 +51,39 @@ calculate_light_color_fancy(void *data,
|
||||
Py_DECREF(color);
|
||||
}
|
||||
|
||||
/* figures out the color from a given skylight and blocklight, used in
|
||||
lighting calculations -- note this is *different* from the one above
|
||||
(the "skylight - 11" part)
|
||||
*/
|
||||
static void
|
||||
calculate_light_color_night(void *data,
|
||||
unsigned char skylight, unsigned char blocklight,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||
unsigned char v = 255 * powf(0.8f, 15.0 - MAX(blocklight, skylight - 11));
|
||||
*r = v;
|
||||
*g = v;
|
||||
*b = v;
|
||||
}
|
||||
|
||||
/* fancy night version that uses the colored light texture */
|
||||
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);
|
||||
unsigned int index;
|
||||
PyObject *color;
|
||||
|
||||
index = skylight + blocklight * 16;
|
||||
color = PySequence_GetItem(mode->lightcolor, index);
|
||||
|
||||
*r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0));
|
||||
*g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
||||
*b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
||||
|
||||
Py_DECREF(color);
|
||||
}
|
||||
|
||||
/* loads the appropriate light data for the given (possibly non-local)
|
||||
* coordinates, and returns a black_coeff this is exposed, so other (derived)
|
||||
* rendermodes can use it
|
||||
@@ -162,9 +195,9 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
PyObject *blocklight = NULL;
|
||||
int local_x = x, local_y = y, local_z = z;
|
||||
unsigned char block, skylevel, blocklevel;
|
||||
|
||||
|
||||
/* find out what chunk we're in, and translate accordingly */
|
||||
if (x >= 0 && y < 16) {
|
||||
if (x >= 0 && x < 16 && y >= 0 && y < 16) {
|
||||
blocks = state->blocks;
|
||||
skylight = self->skylight;
|
||||
blocklight = self->blocklight;
|
||||
@@ -178,13 +211,23 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
blocks = state->right_blocks;
|
||||
skylight = self->right_skylight;
|
||||
blocklight = self->right_blocklight;
|
||||
} else if (y < 0) {
|
||||
local_y += 16;
|
||||
blocks = state->up_left_blocks;
|
||||
skylight = self->up_left_skylight;
|
||||
blocklight = self->up_left_blocklight;
|
||||
} else if (x >= 16) {
|
||||
local_x -= 16;
|
||||
blocks = state->up_right_blocks;
|
||||
skylight = self->up_right_skylight;
|
||||
blocklight = self->up_right_blocklight;
|
||||
}
|
||||
|
||||
/* make sure we have correctly-ranged coordinates */
|
||||
if (!(local_x >= 0 && local_x < 16 &&
|
||||
local_y >= 0 && local_y < 16 &&
|
||||
local_z >= 0 && local_z < 128)) {
|
||||
|
||||
|
||||
self->calculate_light_color(self, 15, 0, r, g, b);
|
||||
return;
|
||||
}
|
||||
@@ -193,7 +236,7 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
if (blocks == Py_None || blocks == NULL ||
|
||||
skylight == Py_None || skylight == NULL ||
|
||||
blocklight == Py_None || blocklight == NULL) {
|
||||
|
||||
|
||||
self->calculate_light_color(self, 15, 0, r, g, b);
|
||||
return;
|
||||
}
|
||||
@@ -236,6 +279,39 @@ get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
self->calculate_light_color(self, MIN(skylevel, 15), MIN(blocklevel, 15), r, g, b);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
/* 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) && !render_mode_hidden(state->rendermode, x, y, z)) {
|
||||
/* this face isn't visible, so don't draw anything */
|
||||
return 1;
|
||||
}
|
||||
} else if (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
|
||||
ugly black doted line between chunks in night rendermode.
|
||||
This wouldn't be necessary if the textures were truly
|
||||
tessellate-able */
|
||||
return 1;
|
||||
}
|
||||
} else if (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
|
||||
ugly black doted line between chunks in night rendermode.
|
||||
This wouldn't be necessary if the textures were truly
|
||||
tessellate-able */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* shades the drawn block with the given facemask, based on the
|
||||
lighting results from (x, y, z) */
|
||||
static inline void
|
||||
@@ -244,33 +320,9 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state,
|
||||
unsigned char r, g, b;
|
||||
float comp_shade_strength;
|
||||
|
||||
/* 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) && !render_mode_hidden(state->rendermode, x, y, z)) {
|
||||
/* this face isn't visible, so don't draw anything */
|
||||
return;
|
||||
}
|
||||
} 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
|
||||
ugly black doted line between chunks in night rendermode.
|
||||
This wouldn't be necessary if the textures were truly
|
||||
tessellate-able */
|
||||
return;
|
||||
}
|
||||
} 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
|
||||
ugly black doted line between chunks in night rendermode.
|
||||
This wouldn't be necessary if the textures were truly
|
||||
tessellate-able */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* check occlusion */
|
||||
if (rendermode_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;
|
||||
@@ -300,6 +352,10 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
if (!render_mode_parse_option(options, "shade_strength", "f", &(self->shade_strength)))
|
||||
return 1;
|
||||
|
||||
self->night = 0;
|
||||
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;
|
||||
@@ -316,8 +372,16 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
self->left_blocklight = PyObject_GetAttrString(state->self, "left_blocklight");
|
||||
self->right_skylight = PyObject_GetAttrString(state->self, "right_skylight");
|
||||
self->right_blocklight = PyObject_GetAttrString(state->self, "right_blocklight");
|
||||
self->up_left_skylight = PyObject_GetAttrString(state->self, "up_left_skylight");
|
||||
self->up_left_blocklight = PyObject_GetAttrString(state->self, "up_left_blocklight");
|
||||
self->up_right_skylight = PyObject_GetAttrString(state->self, "up_right_skylight");
|
||||
self->up_right_blocklight = PyObject_GetAttrString(state->self, "up_right_blocklight");
|
||||
|
||||
self->calculate_light_color = calculate_light_color;
|
||||
if (self->night) {
|
||||
self->calculate_light_color = calculate_light_color_night;
|
||||
} else {
|
||||
self->calculate_light_color = calculate_light_color;
|
||||
}
|
||||
|
||||
if (self->color_light) {
|
||||
self->lightcolor = PyObject_CallMethod(state->textures, "loadLightColor", "");
|
||||
@@ -326,7 +390,11 @@ rendermode_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
self->lightcolor = NULL;
|
||||
self->color_light = 0;
|
||||
} else {
|
||||
self->calculate_light_color = calculate_light_color_fancy;
|
||||
if (self->night) {
|
||||
self->calculate_light_color = calculate_light_color_fancy_night;
|
||||
} else {
|
||||
self->calculate_light_color = calculate_light_color_fancy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self->lightcolor = NULL;
|
||||
@@ -347,6 +415,10 @@ rendermode_lighting_finish(void *data, RenderState *state) {
|
||||
Py_DECREF(self->left_blocklight);
|
||||
Py_DECREF(self->right_skylight);
|
||||
Py_DECREF(self->right_blocklight);
|
||||
Py_DECREF(self->up_left_skylight);
|
||||
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);
|
||||
@@ -403,6 +475,7 @@ 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}
|
||||
};
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
#include <math.h>
|
||||
|
||||
/* figures out the color 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 void
|
||||
calculate_light_color(void *data,
|
||||
unsigned char skylight, unsigned char blocklight,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b) {
|
||||
unsigned char v = 255 * powf(0.8f, 15.0 - MAX(blocklight, skylight - 11));
|
||||
*r = v;
|
||||
*g = v;
|
||||
*b = v;
|
||||
}
|
||||
|
||||
/* fancy version that uses the colored light texture */
|
||||
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);
|
||||
unsigned int index;
|
||||
PyObject *color;
|
||||
|
||||
index = skylight + blocklight * 16;
|
||||
color = PySequence_GetItem(mode->lightcolor, index);
|
||||
|
||||
*r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0));
|
||||
*g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
||||
*b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
||||
|
||||
Py_DECREF(color);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_night_start(void *data, RenderState *state, PyObject *options) {
|
||||
RenderModeNight* self;
|
||||
|
||||
/* first, chain up */
|
||||
int ret = rendermode_lighting.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* override the darkness function with our night version! */
|
||||
self = (RenderModeNight *)data;
|
||||
self->parent.calculate_light_color = calculate_light_color;
|
||||
if (self->parent.color_light)
|
||||
self->parent.calculate_light_color = calculate_light_color_fancy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_night_finish(void *data, RenderState *state) {
|
||||
/* nothing special to do */
|
||||
rendermode_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_night_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special occlusion here */
|
||||
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
|
||||
rendermode_night_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
/* nothing special to do */
|
||||
rendermode_lighting.draw(data, state, src, mask, mask_light);
|
||||
}
|
||||
|
||||
RenderModeInterface rendermode_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,
|
||||
};
|
||||
271
overviewer_core/src/rendermode-smooth-lighting.c
Normal file
271
overviewer_core/src/rendermode-smooth-lighting.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* 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"
|
||||
#include <math.h>
|
||||
|
||||
/* structure representing one corner of a face (see below) */
|
||||
struct SmoothLightingCorner {
|
||||
/* where this corner shows up on each block texture */
|
||||
int imgx, imgy;
|
||||
|
||||
/* the two block offsets that (together) determine the 4 blocks to use */
|
||||
int dx1, dy1, dz1;
|
||||
int dx2, dy2, dz2;
|
||||
};
|
||||
|
||||
/* structure for rule table handling lighting */
|
||||
struct SmoothLightingFace {
|
||||
/* offset from current coordinate to the block this face points towards
|
||||
used for occlusion calculations, and as a base for later */
|
||||
int dx, dy, dz;
|
||||
|
||||
/* the points that form the corners of this face */
|
||||
struct SmoothLightingCorner corners[4];
|
||||
|
||||
/* pairs of (x,y) in order, as touch-up points, or NULL for none */
|
||||
int *touch_up_points;
|
||||
unsigned int num_touch_up_points;
|
||||
};
|
||||
|
||||
/* top face touchups, pulled from textures.py (_build_block) */
|
||||
static int top_touchups[] = {3, 4, 7, 2, 11, 0};
|
||||
|
||||
/* the lighting face rule list! */
|
||||
static struct SmoothLightingFace lighting_rules[] = {
|
||||
/* since this is getting a little insane, here's the general layout:
|
||||
|
||||
{dx, dy, dz, { // direction this face is towards
|
||||
// now, a list of 4 corners...
|
||||
{imgx, imgy, // where the corner is on the block image
|
||||
x1, y1, z1, // two vectors, describing the 4 (!!!)
|
||||
x2, y2, z2}, // blocks neighboring this corner
|
||||
// ...
|
||||
},
|
||||
{x, y, x, y}, 2}, // touch-up points, and how many there are (may be NULL)
|
||||
|
||||
// ...
|
||||
|
||||
*/
|
||||
|
||||
/* top */
|
||||
{0, 0, 1, {
|
||||
{0, 6,
|
||||
-1, 0, 0,
|
||||
0, -1, 0},
|
||||
{12, 0,
|
||||
1, 0, 0,
|
||||
0, -1, 0},
|
||||
{24, 6,
|
||||
1, 0, 0,
|
||||
0, 1, 0},
|
||||
{12, 12,
|
||||
-1, 0, 0,
|
||||
0, 1, 0},
|
||||
},
|
||||
top_touchups, 3},
|
||||
|
||||
/* left */
|
||||
{-1, 0, 0, {
|
||||
{0, 18,
|
||||
0, -1, 0,
|
||||
0, 0, -1},
|
||||
{0, 6,
|
||||
0, -1, 0,
|
||||
0, 0, 1},
|
||||
{12, 12,
|
||||
0, 1, 0,
|
||||
0, 0, 1},
|
||||
{12, 24,
|
||||
0, 1, 0,
|
||||
0, 0, -1},
|
||||
},
|
||||
NULL, 0},
|
||||
|
||||
/* right */
|
||||
{0, 1, 0, {
|
||||
{24, 6,
|
||||
1, 0, 0,
|
||||
0, 0, 1},
|
||||
{12, 12,
|
||||
-1, 0, 0,
|
||||
0, 0, 1},
|
||||
{12, 24,
|
||||
-1, 0, 0,
|
||||
0, 0, -1},
|
||||
{24, 18,
|
||||
1, 0, 0,
|
||||
0, 0, -1},
|
||||
},
|
||||
NULL, 0},
|
||||
};
|
||||
|
||||
/* helpers for indexing the rule list */
|
||||
enum
|
||||
{
|
||||
FACE_TOP = 0,
|
||||
FACE_LEFT = 1,
|
||||
FACE_RIGHT = 2,
|
||||
};
|
||||
|
||||
static void
|
||||
do_shading_with_rule(RenderModeSmoothLighting *self, RenderState *state, struct SmoothLightingFace face) {
|
||||
int i;
|
||||
RenderModeLighting *lighting = (RenderModeLighting *)self;
|
||||
int x = state->imgx, y = state->imgy;
|
||||
struct SmoothLightingCorner *pts = face.corners;
|
||||
float comp_shade_strength = 1.0 - lighting->shade_strength;
|
||||
unsigned char pts_r[4] = {0, 0, 0, 0};
|
||||
unsigned char pts_g[4] = {0, 0, 0, 0};
|
||||
unsigned char pts_b[4] = {0, 0, 0, 0};
|
||||
int cx = state->x + face.dx;
|
||||
int cy = state->y + face.dy;
|
||||
int cz = state->z + face.dz;
|
||||
|
||||
/* first, check for occlusion if the block is in the local chunk */
|
||||
if (rendermode_lighting_is_face_occluded(state, 0, cx, cy, cz))
|
||||
return;
|
||||
|
||||
/* calculate the lighting colors for each point */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
unsigned char r, g, b;
|
||||
unsigned int rgather = 0, ggather = 0, bgather = 0;
|
||||
|
||||
get_lighting_color(lighting, state, cx, cy, cz,
|
||||
&r, &g, &b);
|
||||
rgather += r; ggather += g; bgather += b;
|
||||
|
||||
get_lighting_color(lighting, state,
|
||||
cx+pts[i].dx1, cy+pts[i].dy1, cz+pts[i].dz1,
|
||||
&r, &g, &b);
|
||||
rgather += r; ggather += g; bgather += b;
|
||||
|
||||
get_lighting_color(lighting, state,
|
||||
cx+pts[i].dx2, cy+pts[i].dy2, cz+pts[i].dz2,
|
||||
&r, &g, &b);
|
||||
rgather += r; ggather += g; bgather += b;
|
||||
|
||||
/* FIXME special far corner handling */
|
||||
get_lighting_color(lighting, state,
|
||||
cx+pts[i].dx1+pts[i].dx2, cy+pts[i].dy1+pts[i].dy2, cz+pts[i].dz1+pts[i].dz2,
|
||||
&r, &g, &b);
|
||||
rgather += r; ggather += g; bgather += b;
|
||||
|
||||
rgather += (255*4 - rgather) * comp_shade_strength;
|
||||
ggather += (255*4 - ggather) * comp_shade_strength;
|
||||
bgather += (255*4 - bgather) * comp_shade_strength;
|
||||
|
||||
pts_r[i] = rgather / 4;
|
||||
pts_g[i] = ggather / 4;
|
||||
pts_b[i] = bgather / 4;
|
||||
}
|
||||
|
||||
/* draw the face */
|
||||
draw_triangle(state->img, 1,
|
||||
x+pts[0].imgx, y+pts[0].imgy, pts_r[0], pts_g[0], pts_b[0],
|
||||
x+pts[1].imgx, y+pts[1].imgy, pts_r[1], pts_g[1], pts_b[1],
|
||||
x+pts[2].imgx, y+pts[2].imgy, pts_r[2], pts_g[2], pts_b[2],
|
||||
x, y, face.touch_up_points, face.num_touch_up_points);
|
||||
draw_triangle(state->img, 0,
|
||||
x+pts[0].imgx, y+pts[0].imgy, pts_r[0], pts_g[0], pts_b[0],
|
||||
x+pts[2].imgx, y+pts[2].imgy, pts_r[2], pts_g[2], pts_b[2],
|
||||
x+pts[3].imgx, y+pts[3].imgy, pts_r[3], pts_g[3], pts_b[3],
|
||||
x, y, NULL, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_start(void *data, RenderState *state, PyObject *options) {
|
||||
/* first, chain up */
|
||||
int ret = rendermode_lighting.start(data, state, options);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rendermode_smooth_lighting_finish(void *data, RenderState *state) {
|
||||
/* nothing special to do */
|
||||
rendermode_lighting.finish(data, state);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_occluded(void *data, RenderState *state, int x, int y, int z) {
|
||||
/* no special occlusion here */
|
||||
return rendermode_lighting.occluded(data, state, x, y, z);
|
||||
}
|
||||
|
||||
static int
|
||||
rendermode_smooth_lighting_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
|
||||
rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||
int light_top = 1;
|
||||
int light_left = 1;
|
||||
int light_right = 1;
|
||||
RenderModeSmoothLighting *self = (RenderModeSmoothLighting *)data;
|
||||
|
||||
/* special case for leaves, water 8, water 9
|
||||
-- these are also smooth-lit! */
|
||||
if (state->block != 18 && state->block != 8 && state->block != 9 && is_transparent(state->block))
|
||||
{
|
||||
/* transparent blocks are rendered as usual, with flat lighting */
|
||||
rendermode_lighting.draw(data, state, src, mask, mask_light);
|
||||
return;
|
||||
}
|
||||
|
||||
/* non-transparent blocks get the special smooth treatment */
|
||||
|
||||
/* nothing special to do, but we do want to avoid vanilla
|
||||
* lighting mode draws */
|
||||
rendermode_normal.draw(data, state, src, mask, mask_light);
|
||||
|
||||
/* special code for water */
|
||||
if (state->block == 9)
|
||||
{
|
||||
if (!(state->block_pdata & (1 << 4)))
|
||||
light_top = 0;
|
||||
if (!(state->block_pdata & (1 << 1)))
|
||||
light_left = 0;
|
||||
if (!(state->block_pdata & (1 << 2)))
|
||||
light_right = 0;
|
||||
}
|
||||
|
||||
if (light_top)
|
||||
do_shading_with_rule(self, state, lighting_rules[FACE_TOP]);
|
||||
if (light_left)
|
||||
do_shading_with_rule(self, state, lighting_rules[FACE_LEFT]);
|
||||
if (light_right)
|
||||
do_shading_with_rule(self, state, lighting_rules[FACE_RIGHT]);
|
||||
}
|
||||
|
||||
RenderModeInterface rendermode_smooth_lighting = {
|
||||
"smooth-lighting", "Smooth Lighting",
|
||||
"like \"lighting\", except smooth",
|
||||
NULL,
|
||||
&rendermode_lighting,
|
||||
sizeof(RenderModeSmoothLighting),
|
||||
rendermode_smooth_lighting_start,
|
||||
rendermode_smooth_lighting_finish,
|
||||
rendermode_smooth_lighting_occluded,
|
||||
rendermode_smooth_lighting_hidden,
|
||||
rendermode_smooth_lighting_draw,
|
||||
};
|
||||
@@ -25,7 +25,7 @@
|
||||
static RenderModeInterface *render_modes[] = {
|
||||
&rendermode_normal,
|
||||
&rendermode_lighting,
|
||||
&rendermode_night,
|
||||
&rendermode_smooth_lighting,
|
||||
&rendermode_spawn,
|
||||
&rendermode_cave,
|
||||
&rendermode_mineral,
|
||||
|
||||
@@ -165,6 +165,8 @@ typedef struct {
|
||||
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;
|
||||
@@ -180,15 +182,24 @@ typedef struct {
|
||||
|
||||
float shade_strength;
|
||||
int color_light;
|
||||
int night;
|
||||
} RenderModeLighting;
|
||||
extern RenderModeInterface rendermode_lighting;
|
||||
|
||||
/* NIGHT */
|
||||
/* 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);
|
||||
|
||||
/* exposed so sub-modes can look at colors directly */
|
||||
void get_lighting_color(RenderModeLighting *self, RenderState *state,
|
||||
int x, int y, int z,
|
||||
unsigned char *r, unsigned char *g, unsigned char *b);
|
||||
|
||||
/* SMOOTH LIGHTING */
|
||||
typedef struct {
|
||||
/* inherits from lighting */
|
||||
RenderModeLighting parent;
|
||||
} RenderModeNight;
|
||||
extern RenderModeInterface rendermode_night;
|
||||
} RenderModeSmoothLighting;
|
||||
extern RenderModeInterface rendermode_smooth_lighting;
|
||||
|
||||
/* SPAWN */
|
||||
typedef struct {
|
||||
|
||||
Reference in New Issue
Block a user