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 )
*/
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;

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

View File

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

View File

@@ -18,10 +18,144 @@
#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];
};
/* 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 = {

View File

@@ -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 */