/* 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); }
void overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { RenderPrimitiveOverlay *self = (RenderPrimitiveOverlay *)data; unsigned char r, g, b, a; unsigned short top_block; // exactly analogous to edge-line code for these special blocks int increment=0; if (state->block == 44) // half-step increment=6; else if (state->block == 78) // snow increment=9; /* skip rendering the overlay if we can't see it */ top_block = get_data(state, BLOCKS, state->x, state->y+1, state->z); if (!is_transparent(top_block)) { return; } /* check to be sure this block is solid/fluid */ if (block_has_property(top_block, SOLID) || block_has_property(top_block, FLUID)) { /* top block is fluid or solid, skip drawing */ return; } /* check to be sure this block is solid/fluid */ if (!block_has_property(state->block, SOLID) && !block_has_property(state->block, FLUID)) { /* not fluid or solid, skip drawing the overlay */ return; } /* get our color info */ self->get_color(data, state, &r, &g, &b, &a); /* do the overlay */ if (a > 0) { alpha_over_full(state->img, self->white_color, self->facemask_top, a/255.f, state->imgx, state->imgy + increment, 0, 0); tint_with_mask(state->img, r, g, b, 255, self->facemask_top, state->imgx, state->imgy + increment, 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); }
static void rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { RenderModeNormal *self = (RenderModeNormal *)data; /* draw the block! */ alpha_over(state->img, src, mask, state->imgx, state->imgy, 0, 0); /* check for biome-compatible blocks * * NOTES for maintainers: * * To add a biome-compatible block, add an OR'd condition to this * following if block, a case to the first switch statement to handle when * biome info IS available, and another case to the second switch * statement for when biome info ISN'T available. * * Make sure that in textures.py, the generated textures are the * biome-compliant ones! The tinting is now all done here. */ if (/* grass, but not snowgrass */ (state->block == 2 && !(state->z < 127 && getArrayByte3D(state->blocks, state->x, state->y, state->z+1) == 78)) || /* water */ state->block == 8 || state->block == 9 || /* leaves */ state->block == 18 || /* tallgrass, but not dead shrubs */ (state->block == 31 && state->block_data != 0) || /* pumpkin/melon stem, not fully grown. Fully grown stems * get constant brown color (see textures.py) */ (((state->block == 104) || (state->block == 105)) && (state->block_data != 7)) || /* vines */ state->block == 106 || /* lily pads */ state->block == 111) { /* do the biome stuff! */ PyObject *facemask = mask; unsigned char r, g, b; if (state->block == 2) { /* grass needs a special facemask */ facemask = self->grass_texture; } if (self->biome_data) { /* we have data, so use it! */ unsigned int index; PyObject *color = NULL; index = ((self->chunk_y * 16) + state->y) * 16 * 32 + (self->chunk_x * 16) + state->x; index = big_endian_ushort(getArrayShort1D(self->biome_data, index)); switch (state->block) { case 2: /* grass */ color = PySequence_GetItem(self->grasscolor, index); break; case 8: case 9: /* water */ if (self->watercolor) { color = PySequence_GetItem(self->watercolor, index); } else { color = NULL; facemask = NULL; } break; case 18: /* leaves */ if (state->block_data != 2) { /* not birch! */ color = PySequence_GetItem(self->foliagecolor, index); } else { /* birch! birch foliage color is flipped XY-ways */ unsigned int index_x = 255 - (index % 256); unsigned int index_y = 255 - (index / 256); index = index_y * 256 + index_x; color = PySequence_GetItem(self->foliagecolor, index); } break; case 31: /* tall grass */ color = PySequence_GetItem(self->grasscolor, index); break; case 104: /* pumpkin stem */ color = PySequence_GetItem(self->grasscolor, index); break; case 105: /* melon stem */ color = PySequence_GetItem(self->grasscolor, index); break; case 106: /* vines */ color = PySequence_GetItem(self->grasscolor, index); break; case 111: /* lily padas */ color = PySequence_GetItem(self->grasscolor, index); break; default: break; }; if (color) { /* we've got work to do */ r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); Py_DECREF(color); } } else { if (state->block == 2 || state->block == 31 || state->block == 104 || state->block == 105) /* grass and pumpkin/melon stems */ { r = 115; g = 175; b = 71; } if (state->block == 8 || state->block == 9) /* water */ { /* by default water is fine with nothing */ facemask = NULL; } if (state->block == 18 || state->block == 106 || state->block == 111) /* leaves, vines and lyli pads */ { r = 37; g = 118; b = 25; } } if (facemask) tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0); } if (self->height_fading) { /* do some height fading */ PyObject *height_color = self->white_color; /* negative alpha => darkness, positive => light */ float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55; if (alpha < 0.0) { alpha *= -1; height_color = self->black_color; } alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0); } /* Draw some edge lines! */ // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1) if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) { Imaging img_i = imaging_python_to_c(state->img); unsigned char ink[] = {0, 0, 0, 255 * self->edge_opacity}; int increment=0; if (state->block == 44) // half-step increment=6; else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off) increment=9; if ((state->x == 15) && (state->up_right_blocks != Py_None)) { unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z); if (side_block != state->block && is_transparent(side_block)) { ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1); } } else if (state->x != 15) { unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z); if (side_block != state->block && is_transparent(side_block)) { ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1); } } // if y != 0 and blocks[x,y-1,z] == 0 // chunk boundries are annoying if ((state->y == 0) && (state->up_left_blocks != Py_None)) { unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z); if (side_block != state->block && is_transparent(side_block)) { ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1); } } else if (state->y != 0) { unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z); if (side_block != state->block && is_transparent(side_block)) { // draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1) ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1); } } } }
/* convenience alpha_over with 1.0 as overall_alpha */ inline PyObject* alpha_over(PyObject *dest, PyObject *src, PyObject *mask, int dx, int dy, int xsize, int ysize) { return alpha_over_full(dest, src, mask, 1.0f, dx, dy, xsize, ysize); }