/* shades the drawn block with the given facemask/black_color, based on the lighting results from (x, y, z) */ static inline void do_shading_with_mask(RenderModeLighting *self, RenderState *state, int x, int y, int z, PyObject *mask) { float black_coeff; /* 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; } } black_coeff = get_lighting_coefficient(self, state, x, y, z, NULL); alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0); }
/* shades the drawn block with the given facemask/black_color, based on the lighting results from (x, y, z) */ static inline void do_shading_with_mask(RenderModeLighting *self, RenderState *state, int x, int y, int z, PyObject *mask) { float black_coeff; /* 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; } } black_coeff = get_lighting_coefficient(self, state, x, y, z); black_coeff *= self->shade_strength; alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0); }
/* 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 * * authoratative is a return slot for whether or not this lighting calculation * is true, or a guess. If we guessed, *authoratative will be false, but if it * was calculated correctly from available light data, it will be true. You * may (and probably should) pass NULL. */ inline float get_lighting_coefficient(RenderModeLighting *self, RenderState *state, int x, int y, int z, int *authoratative) { /* 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; unsigned char block, skylevel, blocklevel; /* defaults to "guess" until told otherwise */ if (authoratative) *authoratative = 0; /* 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 = state->left_blocks; skylight = self->left_skylight; blocklight = self->left_blocklight; } else if (y >= 16) { local_y -= 16; blocks = state->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); } block = getArrayByte3D(blocks, local_x, local_y, local_z); /* if this block is opaque, use a fully-lit coeff instead to prevent stippled lines along chunk boundaries! */ if (!is_transparent(block)) { return self->calculate_darkness(15, 0); } /* only do special half-step handling if no authoratative pointer was passed in, which is a sign that we're recursing */ if (block == 44 && authoratative == NULL) { float average_gather = 0.0f; unsigned int average_count = 0; int auth; float coeff; /* iterate through all surrounding blocks to take an average */ int dx, dy, dz; for (dx = -1; dx <= 1; dx += 2) { for (dy = -1; dy <= 1; dy += 2) { for (dz = -1; dz <= 1; dz += 2) { coeff = get_lighting_coefficient(self, state, x+dx, y+dy, z+dz, &auth); if (auth) { average_gather += coeff; average_count++; } } } } /* only return the average if at least one was authoratative */ if (average_count > 0) return average_gather / average_count; } if (block == 10 || block == 11) { /* lava blocks should always be lit! */ return 0.0f; } skylevel = getArrayByte3D(skylight, local_x, local_y, local_z); blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z); /* no longer a guess */ if (authoratative) *authoratative = 1; return self->calculate_darkness(skylevel, blocklevel); }