static void
rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    RenderModeOverlay *self = (RenderModeOverlay *)data;
    unsigned char r, g, b, a;
    PyObject *top_block_py, *block_py;
    
    // 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;
    
    /* clear the draw space -- set alpha to 0 within mask */
    tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0);

    /* skip rendering the overlay if we can't see it */
    if (state->z != 127) {
        unsigned char top_block = getArrayByte3D(state->blocks, state->x, state->y, state->z+1);
        if (!is_transparent(top_block)) {
            return;
        }
        
        /* check to be sure this block is solid/fluid */
        top_block_py = PyInt_FromLong(top_block);
        if (PySequence_Contains(self->solid_blocks, top_block_py) ||
            PySequence_Contains(self->fluid_blocks, top_block_py)) {
            
            /* top block is fluid or solid, skip drawing */
            Py_DECREF(top_block_py);
            return;
        }
        Py_DECREF(top_block_py);
    }
    
    /* check to be sure this block is solid/fluid */
    block_py = PyInt_FromLong(state->block);
    if (!PySequence_Contains(self->solid_blocks, block_py) &&
        !PySequence_Contains(self->fluid_blocks, block_py)) {
        
        /* not fluid or solid, skip drawing the overlay */
        Py_DECREF(block_py);
        return;
    }
    Py_DECREF(block_py);

    /* get our color info */
    self->get_color(data, state, &r, &g, &b, &a);
    
    /* do the overlay */
    if (a > 0) {
        alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy + increment, 0, 0);
        tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy + increment, 0, 0);
    }
}
/* properly refs the return value when needed: you DO need to decref the return */
PyObject *
alpha_over_wrap(PyObject *self, PyObject *args)
{
    /* raw input python variables */
    PyObject *dest, *src, *pos = NULL, *mask = NULL;
    /* destination position and size */
    int dx, dy, xsize, ysize;
    /* return value: dest image on success */
    PyObject *ret;

    if (!PyArg_ParseTuple(args, "OO|OO", &dest, &src, &pos, &mask))
        return NULL;
    
    if (mask == NULL)
        mask = src;
    
    /* destination position read */
    if (pos == NULL) {
        xsize = 0;
        ysize = 0;
        dx = 0;
        dy = 0;
    } else {
        if (!PyArg_ParseTuple(pos, "iiii", &dx, &dy, &xsize, &ysize)) {
            /* try again, but this time try to read a point */
            PyErr_Clear();
            xsize = 0;
            ysize = 0;
            if (!PyArg_ParseTuple(pos, "ii", &dx, &dy)) {
                PyErr_SetString(PyExc_TypeError,
                                "given blend destination rect is not valid");
                return NULL;
            }
        }
    }

    ret = alpha_over(dest, src, mask, dx, dy, xsize, ysize);
    if (ret == dest) {
        /* Python needs us to own our return value */
        Py_INCREF(dest);
    }
    return ret;
}
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);
            }
        }
    }
}
Example #4
0
static void
base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    PrimitiveBase *self = (PrimitiveBase *)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, and a case to the switch statement to handle biome
     * coloring.
     *
     * 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 && get_data(state, BLOCKS, state->x, state->y+1, state->z) != 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 = 255, g = 255, b = 255;
        PyObject *color_table = NULL;
        unsigned char flip_xy = 0;
        
        if (state->block == 2) {
            /* grass needs a special facemask */
            facemask = self->grass_texture;
        }

        switch (state->block) {
        case 2:
            /* grass */
            color_table = self->grasscolor;
            break;
        case 8:
        case 9:
            /* water */
            color_table = self->watercolor;
            break;
        case 18:
            /* leaves */
            color_table = self->foliagecolor;
            if (state->block_data == 2)
            {
                /* birch!
                   birch foliage color is flipped XY-ways */
                flip_xy = 1;
            }
            break;
        case 31:
            /* tall grass */
            color_table = self->grasscolor;
            break;
        case 104:
            /* pumpkin stem */
            color_table = self->grasscolor;
            break;
        case 105:
            /* melon stem */
            color_table = self->grasscolor;
            break;
        case 106:
            /* vines */
            color_table = self->grasscolor;
            break;
        case 111:
            /* lily pads */
            color_table = self->grasscolor;
            break;
        default:
            break;
        };
            
        if (color_table) {
            unsigned char biome;
            int dx, dz;
            unsigned char tablex, tabley;
            float temp = 0.0, rain = 0.0;
            unsigned int multr = 0, multg = 0, multb = 0;
            int tmp;
            PyObject *color = NULL;
            
            if (self->use_biomes) {
                /* average over all neighbors */
                for (dx = -1; dx <= 1; dx++) {
                    for (dz = -1; dz <= 1; dz++) {
                        biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz);
                        if (biome >= NUM_BIOMES) {
                            /* note -- biome 255 shows up on map borders.
                               who knows what it is? certainly not I.
                            */
                            biome = DEFAULT_BIOME; /* forest -- reasonable default */
                        }
                    
                        temp += biome_table[biome].temperature;
                        rain += biome_table[biome].rainfall;
                        multr += biome_table[biome].r;
                        multg += biome_table[biome].g;
                        multb += biome_table[biome].b;
                    }
                }
                
                temp /= 9.0;
                rain /= 9.0;
                multr /= 9;
                multg /= 9;
                multb /= 9;
            } else {
                /* don't use biomes, just use the default */
                temp = biome_table[DEFAULT_BIOME].temperature;
                rain = biome_table[DEFAULT_BIOME].rainfall;
                multr = biome_table[DEFAULT_BIOME].r;
                multg = biome_table[DEFAULT_BIOME].g;
                multb = biome_table[DEFAULT_BIOME].b;
            }
            
            /* second coordinate is actually scaled to fit inside the triangle
               so store it in rain */
            rain *= temp;
            
            /* make sure they're sane */
            temp = CLAMP(temp, 0.0, 1.0);
            rain = CLAMP(rain, 0.0, 1.0);
            
            /* convert to x/y coordinates in color table */
            tablex = 255 - (255 * temp);
            tabley = 255 - (255 * rain);
            if (flip_xy) {
                unsigned char tmp = 255 - tablex;
                tablex = 255 - tabley;
                tabley = tmp;
            }
            
            /* look up color! */
            color = PySequence_GetItem(color_table, tabley * 256 + tablex);
            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);
            
            /* do the after-coloration */
            r = MULDIV255(r, multr, tmp);
            g = MULDIV255(g, multg, tmp);
            b = MULDIV255(b, multb, tmp);
        }
        
        /* final coloration */
        tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
    }
}