From 2705a1efe874d50305486b22a08ea2af6d0ca2ae Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 16 Oct 2011 17:18:24 -0400 Subject: [PATCH] smooth-lighting triangles now pull lighting data correctly for each vertex --- overviewer_core/src/composite.c | 5 +- overviewer_core/src/overviewer.h | 2 +- overviewer_core/src/rendermode-lighting.c | 69 ++++--- .../src/rendermode-smooth-lighting.c | 175 ++++++++++++++---- overviewer_core/src/rendermodes.h | 8 + 5 files changed, 193 insertions(+), 66 deletions(-) diff --git a/overviewer_core/src/composite.c b/overviewer_core/src/composite.c index 1c4ba1d..271f558 100644 --- a/overviewer_core/src/composite.c +++ b/overviewer_core/src/composite.c @@ -369,7 +369,7 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, * http://www.gidforums.com/t-20838.html ) */ PyObject * -draw_triangle(PyObject *dest, +draw_triangle(PyObject *dest, int inclusive, int x0, int y0, unsigned char r0, unsigned char g0, unsigned char b0, int x1, int y1, @@ -433,7 +433,8 @@ draw_triangle(PyObject *dest, beta = beta_norm * ((a20 * x) + (b20 * y) + c20); gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01); - if (alpha >= 0 && beta >= 0 && gamma >= 0) { + 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; diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 8aecfa8..f08ecf6 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -51,7 +51,7 @@ 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, +PyObject *draw_triangle(PyObject *dest, int inclusive, int x0, int y0, unsigned char r0, unsigned char g0, unsigned char b0, int x1, int y1, diff --git a/overviewer_core/src/rendermode-lighting.c b/overviewer_core/src/rendermode-lighting.c index 395061a..e4a9254 100644 --- a/overviewer_core/src/rendermode-lighting.c +++ b/overviewer_core/src/rendermode-lighting.c @@ -162,7 +162,7 @@ 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) { blocks = state->blocks; @@ -184,7 +184,7 @@ get_lighting_color(RenderModeLighting *self, RenderState *state, 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 +193,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 +236,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 +277,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; diff --git a/overviewer_core/src/rendermode-smooth-lighting.c b/overviewer_core/src/rendermode-smooth-lighting.c index 2384440..38e500e 100644 --- a/overviewer_core/src/rendermode-smooth-lighting.c +++ b/overviewer_core/src/rendermode-smooth-lighting.c @@ -18,10 +18,144 @@ #include "overviewer.h" #include +/* 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]; +}; + +/* the lighting face rule list! */ +static struct SmoothLightingFace lighting_rules[] = { + /* 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}, + }}, + /* left */ + {-1, 0, 0, { + {12, 24, + 0, 1, 0, + 0, 0, -1}, + {0, 18, + 0, -1, 0, + 0, 0, -1}, + {0, 6, + 0, -1, 0, + 0, 0, 1}, + {12, 12, + 0, 1, 0, + 0, 0, 1}, + }}, + /* right */ + {0, 1, 0, { + {12, 12, + -1, 0, 0, + 0, 0, 1}, + {12, 24, + -1, 0, 0, + 0, 0, -1}, + {24, 18, + 1, 0, 0, + 0, 0, -1}, + {24, 6, + 1, 0, 0, + 0, 0, 1}, + }}, +}; + +/* 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; + 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; + + 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]); + 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]); +} + static int rendermode_smooth_lighting_start(void *data, RenderState *state, PyObject *options) { - RenderModeNight* self; - /* first, chain up */ int ret = rendermode_lighting.start(data, state, options); if (ret != 0) @@ -50,9 +184,10 @@ rendermode_smooth_lighting_hidden(void *data, RenderState *state, int x, int y, static void rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { - int x = state->imgx, y = state->imgy; + RenderModeSmoothLighting *self = (RenderModeSmoothLighting *)data; - if (is_transparent(state->block)) + /* special case for leaves -- these are also smooth-lit! */ + if (state->block != 18 && is_transparent(state->block)) { /* transparent blocks are rendered as usual, with flat lighting */ rendermode_lighting.draw(data, state, src, mask, mask_light); @@ -65,35 +200,9 @@ rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, P * lighting mode draws */ rendermode_normal.draw(data, state, src, mask, mask_light); - /* draw a triangle on top of each block */ - draw_triangle(state->img, - x+12, y, 255, 0, 0, - x+24, y+6, 0, 255, 0, - x, y+6, 0, 0, 255); - draw_triangle(state->img, - x+24, y+6, 255, 0, 0, - x, y+6, 0, 255, 0, - x+12, y+12, 0, 0, 255); - - /* left side... */ - draw_triangle(state->img, - x, y+6, 255, 0, 0, - x+12, y+12, 0, 255, 0, - x+12, y+24, 0, 0, 255); - draw_triangle(state->img, - x+12, y+24, 255, 0, 0, - x, y+6, 0, 255, 0, - x, y+18, 0, 0, 255); - - /* right side... */ - draw_triangle(state->img, - x+24, y+6, 255, 0, 0, - x+12, y+12, 0, 255, 0, - x+12, y+24, 0, 0, 255); - draw_triangle(state->img, - x+12, y+24, 255, 0, 0, - x+24, y+6, 0, 255, 0, - x+24, y+18, 0, 0, 255); + do_shading_with_rule(self, state, lighting_rules[FACE_TOP]); + do_shading_with_rule(self, state, lighting_rules[FACE_LEFT]); + do_shading_with_rule(self, state, lighting_rules[FACE_RIGHT]); } RenderModeInterface rendermode_smooth_lighting = { diff --git a/overviewer_core/src/rendermodes.h b/overviewer_core/src/rendermodes.h index 25d774e..a7aa47f 100644 --- a/overviewer_core/src/rendermodes.h +++ b/overviewer_core/src/rendermodes.h @@ -183,6 +183,14 @@ typedef struct { } 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); + +/* 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); + /* NIGHT */ typedef struct { /* inherits from lighting */