0

Merge branch 'smooth-lighting'

This commit is contained in:
Aaron Griffith
2011-11-07 19:46:10 -05:00
18 changed files with 1547 additions and 155 deletions

View File

@@ -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);

View File

@@ -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'},

View File

@@ -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),

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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}
};

View File

@@ -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,
};

View 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,
};

View File

@@ -25,7 +25,7 @@
static RenderModeInterface *render_modes[] = {
&rendermode_normal,
&rendermode_lighting,
&rendermode_night,
&rendermode_smooth_lighting,
&rendermode_spawn,
&rendermode_cave,
&rendermode_mineral,

View File

@@ -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 {