rewrote get_lighting_coefficient in C
This commit is contained in:
@@ -32,6 +32,10 @@
|
||||
/* macro for getting a value out of a 3D numpy byte array */
|
||||
#define getArrayByte3D(array, x,y,z) (*(unsigned char *)(PyArray_GETPTR3((array), (x), (y), (z))))
|
||||
|
||||
/* generally useful MAX / MIN macros */
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/* in composite.c */
|
||||
Imaging imaging_python_to_c(PyObject *obj);
|
||||
PyObject *alpha_over(PyObject *dest, PyObject *src, PyObject *mask, int dx,
|
||||
|
||||
@@ -16,37 +16,94 @@
|
||||
*/
|
||||
|
||||
#include "overviewer.h"
|
||||
#include <math.h>
|
||||
|
||||
/* figures out the black_coeff from a given skylight and blocklight,
|
||||
used in lighting calculations */
|
||||
static float calculate_darkness(unsigned char skylight, unsigned char blocklight) {
|
||||
return 1.0f - powf(0.8f, 15.0 - MAX(blocklight, skylight));
|
||||
}
|
||||
|
||||
/* loads the appropriate light data for the given (possibly non-local)
|
||||
coordinates, and returns a black_coeff */
|
||||
static inline float
|
||||
get_lighting_coefficient(RenderModeLighting *self, RenderState *state, int x, int y, int z) {
|
||||
/* placeholders for later data arrays, coordinates */
|
||||
PyObject *blocks = NULL;
|
||||
PyObject *skylight = NULL;
|
||||
PyObject *blocklight = NULL;
|
||||
int local_x = x, local_y = y, local_z = z;
|
||||
|
||||
/* find out what chunk we're in, and translate accordingly */
|
||||
if (x >= 0 && y < 16) {
|
||||
blocks = state->blocks;
|
||||
skylight = self->skylight;
|
||||
blocklight = self->blocklight;
|
||||
} else if (x < 0) {
|
||||
local_x += 16;
|
||||
blocks = self->left_blocks;
|
||||
skylight = self->left_skylight;
|
||||
blocklight = self->left_blocklight;
|
||||
} else if (y >= 16) {
|
||||
local_y -= 16;
|
||||
blocks = self->right_blocks;
|
||||
skylight = self->right_skylight;
|
||||
blocklight = self->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)) {
|
||||
|
||||
return self->calculate_darkness(15, 0);
|
||||
}
|
||||
|
||||
/* also, make sure we have enough info to correctly calculate lighting */
|
||||
if (blocks == Py_None || blocks == NULL ||
|
||||
skylight == Py_None || skylight == NULL ||
|
||||
blocklight == Py_None || blocklight == NULL) {
|
||||
|
||||
return self->calculate_darkness(15, 0);
|
||||
}
|
||||
|
||||
unsigned char block = getArrayByte3D(blocks, local_x, local_y, local_z);
|
||||
|
||||
if (block == 44) {
|
||||
/* TODO special handling for half-blocks! */
|
||||
}
|
||||
|
||||
if (block == 10 || block == 11) {
|
||||
/* lava blocks should always be lit! */
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
unsigned char skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
|
||||
unsigned char blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
|
||||
|
||||
return self->calculate_darkness(skylevel, blocklevel);
|
||||
}
|
||||
|
||||
/* shades the drawn block with the given facemask/black_color, based on the
|
||||
lighting results from (x, y, z) */
|
||||
static inline void
|
||||
do_shading_for_face(PyObject *chunk, int x, int y, int z, PyObject *facemask, PyObject *black_color,
|
||||
PyObject *img, int imgx, int imgy) {
|
||||
// returns new references
|
||||
PyObject* light_tup = PyObject_CallMethod(chunk, "get_lighting_coefficient", "iii", x, y, z);
|
||||
PyObject *black_coeff_py = PySequence_GetItem(light_tup, 0);
|
||||
double black_coeff = PyFloat_AsDouble(black_coeff_py);
|
||||
Py_DECREF(black_coeff_py);
|
||||
|
||||
PyObject *face_occlude_py = PySequence_GetItem(light_tup, 1);
|
||||
int face_occlude = PyInt_AsLong(face_occlude_py);
|
||||
Py_DECREF(face_occlude_py);
|
||||
|
||||
Py_DECREF(light_tup);
|
||||
|
||||
|
||||
if (!face_occlude) {
|
||||
//#composite.alpha_over(img, over_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
|
||||
|
||||
PyObject *mask = PyObject_CallMethod(facemask, "copy", NULL); // new ref
|
||||
//printf("black_coeff: %f\n", black_coeff);
|
||||
brightness(mask, black_coeff);
|
||||
//printf("done with brightness\n");
|
||||
alpha_over(img, black_color, mask, imgx, imgy, 0, 0);
|
||||
//printf("done with alpha_over\n");
|
||||
Py_DECREF(mask);
|
||||
|
||||
do_shading_for_face(RenderModeLighting *self, RenderState *state,
|
||||
int x, int y, int z, PyObject *facemask) {
|
||||
/* 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)) {
|
||||
/* this face isn't visible, so don't draw anything */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float black_coeff = get_lighting_coefficient(self, state, x, y, z);
|
||||
|
||||
PyObject *mask = PyObject_CallMethod(facemask, "copy", NULL); // new ref
|
||||
brightness(mask, black_coeff);
|
||||
alpha_over(state->img, self->black_color, mask, state->imgx, state->imgy, 0, 0);
|
||||
Py_DECREF(mask);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -65,6 +122,19 @@ rendermode_lighting_start(void *data, RenderState *state) {
|
||||
self->facemasks[1] = PyTuple_GetItem(self->facemasks_py, 1);
|
||||
self->facemasks[2] = PyTuple_GetItem(self->facemasks_py, 2);
|
||||
|
||||
self->skylight = PyObject_GetAttrString(state->self, "skylight");
|
||||
self->blocklight = PyObject_GetAttrString(state->self, "blocklight");
|
||||
|
||||
self->left_blocks = PyObject_GetAttrString(state->self, "left_blocks");
|
||||
self->left_skylight = PyObject_GetAttrString(state->self, "left_skylight");
|
||||
self->left_blocklight = PyObject_GetAttrString(state->self, "left_blocklight");
|
||||
|
||||
self->right_blocks = PyObject_GetAttrString(state->self, "right_blocks");
|
||||
self->right_skylight = PyObject_GetAttrString(state->self, "right_skylight");
|
||||
self->right_blocklight = PyObject_GetAttrString(state->self, "right_blocklight");
|
||||
|
||||
self->calculate_darkness = calculate_darkness;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -75,6 +145,17 @@ rendermode_lighting_finish(void *data, RenderState *state) {
|
||||
Py_DECREF(self->black_color);
|
||||
Py_DECREF(self->facemasks_py);
|
||||
|
||||
Py_DECREF(self->skylight);
|
||||
Py_DECREF(self->blocklight);
|
||||
|
||||
Py_DECREF(self->left_blocks);
|
||||
Py_DECREF(self->left_skylight);
|
||||
Py_DECREF(self->left_blocklight);
|
||||
|
||||
Py_DECREF(self->right_blocks);
|
||||
Py_DECREF(self->right_skylight);
|
||||
Py_DECREF(self->right_blocklight);
|
||||
|
||||
/* now chain up */
|
||||
rendermode_normal.finish(data, state);
|
||||
}
|
||||
@@ -91,20 +172,12 @@ rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject
|
||||
rendermode_normal.draw(data, state, src, mask);
|
||||
|
||||
RenderModeLighting* self = (RenderModeLighting *)data;
|
||||
|
||||
PyObject *chunk = state->self;
|
||||
int x = state->x, y = state->y, z = state->z;
|
||||
PyObject **facemasks = self->facemasks;
|
||||
PyObject *black_color = self->black_color, *img = state->img;
|
||||
int imgx = state->imgx, imgy = state->imgy;
|
||||
|
||||
// FIXME whole-block shading for transparent blocks
|
||||
do_shading_for_face(chunk, x, y, z+1, facemasks[0], black_color,
|
||||
img, imgx, imgy);
|
||||
do_shading_for_face(chunk, x-1, y, z, facemasks[1], black_color,
|
||||
img, imgx, imgy);
|
||||
do_shading_for_face(chunk, x, y+1, z, facemasks[2], black_color,
|
||||
img, imgx, imgy);
|
||||
// TODO whole-block shading for transparent blocks
|
||||
do_shading_for_face(self, state, x, y, z+1, self->facemasks[0]);
|
||||
do_shading_for_face(self, state, x-1, y, z, self->facemasks[1]);
|
||||
do_shading_for_face(self, state, x, y+1, z, self->facemasks[2]);
|
||||
}
|
||||
|
||||
RenderModeInterface rendermode_lighting = {
|
||||
|
||||
@@ -70,6 +70,15 @@ typedef struct {
|
||||
|
||||
PyObject *black_color, *facemasks_py;
|
||||
PyObject *facemasks[3];
|
||||
|
||||
/* extra block data, loaded off the chunk class */
|
||||
PyObject *skylight, *blocklight;
|
||||
PyObject *left_blocks, *left_skylight, *left_blocklight;
|
||||
PyObject *right_blocks, *right_skylight, *right_blocklight;
|
||||
|
||||
/* can be overridden in derived rendermodes to control lighting
|
||||
arguments are skylight, blocklight */
|
||||
float (*calculate_darkness)(unsigned char, unsigned char);
|
||||
} RenderModeLighting;
|
||||
extern RenderModeInterface rendermode_lighting;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user