0

smooth-lighting triangles now pull lighting data correctly for each vertex

This commit is contained in:
Aaron Griffith
2011-10-16 17:18:24 -04:00
parent b984185f0c
commit 2705a1efe8
5 changed files with 193 additions and 66 deletions

View File

@@ -369,7 +369,7 @@ tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg,
* http://www.gidforums.com/t-20838.html ) * http://www.gidforums.com/t-20838.html )
*/ */
PyObject * PyObject *
draw_triangle(PyObject *dest, draw_triangle(PyObject *dest, int inclusive,
int x0, int y0, int x0, int y0,
unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r0, unsigned char g0, unsigned char b0,
int x1, int y1, int x1, int y1,
@@ -433,7 +433,8 @@ draw_triangle(PyObject *dest,
beta = beta_norm * ((a20 * x) + (b20 * y) + c20); beta = beta_norm * ((a20 * x) + (b20 * y) + c20);
gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01); 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 r = alpha * r0 + beta * r1 + gamma * r2;
unsigned int g = alpha * g0 + beta * g1 + gamma * g2; unsigned int g = alpha * g0 + beta * g1 + gamma * g2;
unsigned int b = alpha * b0 + beta * b1 + gamma * b2; unsigned int b = alpha * b0 + beta * b1 + gamma * b2;

View File

@@ -51,7 +51,7 @@ PyObject *alpha_over_wrap(PyObject *self, PyObject *args);
PyObject *tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg, PyObject *tint_with_mask(PyObject *dest, unsigned char sr, unsigned char sg,
unsigned char sb, unsigned char sa, unsigned char sb, unsigned char sa,
PyObject *mask, int dx, int dy, int xsize, int ysize); 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, int x0, int y0,
unsigned char r0, unsigned char g0, unsigned char b0, unsigned char r0, unsigned char g0, unsigned char b0,
int x1, int y1, int x1, int y1,

View File

@@ -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); 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 /* 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
@@ -244,33 +277,9 @@ do_shading_with_mask(RenderModeLighting *self, RenderState *state,
unsigned char r, g, b; unsigned char r, g, b;
float comp_shade_strength; float comp_shade_strength;
/* first, check for occlusion if the block is in the local chunk */ /* check occlusion */
if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) { if (rendermode_lighting_is_face_occluded(state, self->skip_sides, x, y, z))
unsigned char block = getArrayByte3D(state->blocks, x, y, z); return;
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;
}
}
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_shade_strength = 1.0 - self->shade_strength;

View File

@@ -18,10 +18,144 @@
#include "overviewer.h" #include "overviewer.h"
#include <math.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];
};
/* 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 static int
rendermode_smooth_lighting_start(void *data, RenderState *state, PyObject *options) { rendermode_smooth_lighting_start(void *data, RenderState *state, PyObject *options) {
RenderModeNight* self;
/* first, chain up */ /* first, chain up */
int ret = rendermode_lighting.start(data, state, options); int ret = rendermode_lighting.start(data, state, options);
if (ret != 0) if (ret != 0)
@@ -50,9 +184,10 @@ rendermode_smooth_lighting_hidden(void *data, RenderState *state, int x, int y,
static void static void
rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { 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 */ /* transparent blocks are rendered as usual, with flat lighting */
rendermode_lighting.draw(data, state, src, mask, mask_light); 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 */ * lighting mode draws */
rendermode_normal.draw(data, state, src, mask, mask_light); rendermode_normal.draw(data, state, src, mask, mask_light);
/* draw a triangle on top of each block */ do_shading_with_rule(self, state, lighting_rules[FACE_TOP]);
draw_triangle(state->img, do_shading_with_rule(self, state, lighting_rules[FACE_LEFT]);
x+12, y, 255, 0, 0, do_shading_with_rule(self, state, lighting_rules[FACE_RIGHT]);
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);
} }
RenderModeInterface rendermode_smooth_lighting = { RenderModeInterface rendermode_smooth_lighting = {

View File

@@ -183,6 +183,14 @@ typedef struct {
} RenderModeLighting; } RenderModeLighting;
extern RenderModeInterface rendermode_lighting; 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 */ /* NIGHT */
typedef struct { typedef struct {
/* inherits from lighting */ /* inherits from lighting */