Пример #1
0
void
ImagingPackBGRa(UINT8* out, const UINT8* in, int pixels)
{
    int i;
    /* BGRa, reversed bytes with premultiplied alpha */
    for (i = 0; i < pixels; i++) {
        int alpha = out[3] = in[A];
        int tmp;
        out[0] = MULDIV255(in[B], alpha, tmp);
        out[1] = MULDIV255(in[G], alpha, tmp);
        out[2] = MULDIV255(in[R], alpha, tmp);
        out += 4; in += 4;
    }
}
Пример #2
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);
    }
}
Пример #3
0
/* like alpha_over, but instead of src image it takes a source color
 * also, it multiplies instead of doing an over operation
 */
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) {
    /* libImaging handles */
    Imaging imDest, imMask;
    /* cached blend properties */
    int mask_offset, mask_stride;
    /* source position */
    int sx, sy;
    /* iteration variables */
    unsigned int x, y;
    /* temporary calculation variables */
    int tmp1, tmp2;

    imDest = imaging_python_to_c(dest);
    imMask = imaging_python_to_c(mask);

    if (!imDest || !imMask)
        return NULL;

    /* check the various image modes, make sure they make sense */
    if (strcmp(imDest->mode, "RGBA") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given destination image does not have mode \"RGBA\"");
        return NULL;
    }

    if (strcmp(imMask->mode, "RGBA") != 0 && strcmp(imMask->mode, "L") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given mask image does not have mode \"RGBA\" or \"L\"");
        return NULL;
    }

    /* how far into image the first alpha byte resides */
    mask_offset = (imMask->pixelsize == 4 ? 3 : 0);
    /* how many bytes to skip to get to the next alpha byte */
    mask_stride = imMask->pixelsize;

    /* setup source & destination vars */
    setup_source_destination(imMask, imDest, &sx, &sy, &dx, &dy, &xsize, &ysize);

    /* check that there remains any blending to be done */
    if (xsize <= 0 || ysize <= 0) {
        /* nothing to do, return */
        return dest;
    }

    for (y = 0; y < ysize; y++) {
        UINT8 *out = (UINT8 *)imDest->image[dy + y] + dx * 4;
        UINT8 *inmask = (UINT8 *)imMask->image[sy + y] + sx * mask_stride + mask_offset;

        for (x = 0; x < xsize; x++) {
            /* special cases */
            if (*inmask == 255) {
                *out = MULDIV255(*out, sr, tmp1);
                out++;
                *out = MULDIV255(*out, sg, tmp1);
                out++;
                *out = MULDIV255(*out, sb, tmp1);
                out++;
                *out = MULDIV255(*out, sa, tmp1);
                out++;
            } else if (*inmask == 0) {
                /* do nothing -- source is fully transparent */
                out += 4;
            } else {
                /* general case */
                
                /* TODO work out general case */
                *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sr, *inmask, tmp1), tmp2);
                out++;
                *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sg, *inmask, tmp1), tmp2);
                out++;
                *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sb, *inmask, tmp1), tmp2);
                out++;
                *out = MULDIV255(*out, (255 - *inmask) + MULDIV255(sa, *inmask, tmp1), tmp2);
                out++;
            }

            inmask += mask_stride;
        }
    }

    return dest;
}
Пример #4
0
/* draws a triangle on the destination image, multiplicatively!
 * used for smooth lighting
 * (excuse the ridiculous number of parameters!)
 *
 * Algorithm adapted from _Fundamentals_of_Computer_Graphics_
 * by Peter Shirley, Michael Ashikhmin
 * (or at least, the version poorly reproduced here:
 *  http://www.gidforums.com/t-20838.html )
 */
PyObject *
draw_triangle(PyObject *dest, int inclusive,
              int x0, int y0,
              unsigned char r0, unsigned char g0, unsigned char b0,
              int x1, int y1,
              unsigned char r1, unsigned char g1, unsigned char b1,
              int x2, int y2,
              unsigned char r2, unsigned char g2, unsigned char b2,
              int tux, int tuy, int *touchups, unsigned int num_touchups) {
    
    /* destination image */
    Imaging imDest;
    /* ranges of pixels that are affected */
    int xmin, xmax, ymin, ymax;
    /* constant coefficients for alpha, beta, gamma */
    int a12, a20, a01;
    int b12, b20, b01;
    int c12, c20, c01;
    /* constant normalizers for alpha, beta, gamma */
    float alpha_norm, beta_norm, gamma_norm;
    /* temporary variables */
    int tmp;
    /* iteration variables */
    int x, y;
    
    imDest = imaging_python_to_c(dest);
    if (!imDest)
        return NULL;

    /* check the various image modes, make sure they make sense */
    if (strcmp(imDest->mode, "RGBA") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given destination image does not have mode \"RGBA\"");
        return NULL;
    }
    
    /* set up draw ranges */
    xmin = MIN(x0, MIN(x1, x2));
    ymin = MIN(y0, MIN(y1, y2));
    xmax = MAX(x0, MAX(x1, x2)) + 1;
    ymax = MAX(y0, MAX(y1, y2)) + 1;
    
    xmin = MAX(xmin, 0);
    ymin = MAX(ymin, 0);
    xmax = MIN(xmax, imDest->xsize);
    ymax = MIN(ymax, imDest->ysize);
    
    /* setup coefficients */
    a12 = y1 - y2; b12 = x2 - x1; c12 = (x1 * y2) - (x2 * y1);
    a20 = y2 - y0; b20 = x0 - x2; c20 = (x2 * y0) - (x0 * y2);
    a01 = y0 - y1; b01 = x1 - x0; c01 = (x0 * y1) - (x1 * y0);
    
    /* setup normalizers */
    alpha_norm = 1.0f / ((a12 * x0) + (b12 * y0) + c12);
    beta_norm  = 1.0f / ((a20 * x1) + (b20 * y1) + c20);
    gamma_norm = 1.0f / ((a01 * x2) + (b01 * y2) + c01);
    
    /* iterate over the destination rect */
    for (y = ymin; y < ymax; y++) {
        UINT8 *out = (UINT8 *)imDest->image[y] + xmin * 4;
        
        for (x = xmin; x < xmax; x++) {
            float alpha, beta, gamma;
            alpha = alpha_norm * ((a12 * x) + (b12 * y) + c12);
            beta  = beta_norm  * ((a20 * x) + (b20 * y) + c20);
            gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01);
            
            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;
                
                *out = MULDIV255(*out, r, tmp); out++;
                *out = MULDIV255(*out, g, tmp); out++;
                *out = MULDIV255(*out, b, tmp); out++;
                
                /* keep alpha the same */
                out++;
            } else {
                /* skip */
                out += 4;
            }
        }
    }
    
    while (num_touchups > 0) {
        float alpha, beta, gamma;
        unsigned int r, g, b;
        UINT8 *out;
        
        x = touchups[0] + tux;
        y = touchups[1] + tuy;
        touchups += 2;
        num_touchups--;
        
        if (x < 0 || x >= imDest->xsize || y < 0 || y >= imDest->ysize)
            continue;

        out = (UINT8 *)imDest->image[y] + x * 4;

        alpha = alpha_norm * ((a12 * x) + (b12 * y) + c12);
        beta  = beta_norm  * ((a20 * x) + (b20 * y) + c20);
        gamma = gamma_norm * ((a01 * x) + (b01 * y) + c01);
        
        r = alpha * r0 + beta * r1 + gamma * r2;
        g = alpha * g0 + beta * g1 + gamma * g2;
        b = alpha * b0 + beta * b1 + gamma * b2;
                
        *out = MULDIV255(*out, r, tmp); out++;
        *out = MULDIV255(*out, g, tmp); out++;
        *out = MULDIV255(*out, b, tmp); out++;
    }
    
    return dest;
}
Пример #5
0
/* the full alpha_over function, in a form that can be called from C
 * overall_alpha is multiplied with the whole mask, useful for lighting...
 * if xsize, ysize are negative, they are instead set to the size of the image in src
 * returns NULL on error, dest on success. You do NOT need to decref the return!
 */
inline PyObject *
alpha_over_full(PyObject *dest, PyObject *src, PyObject *mask, float overall_alpha,
                int dx, int dy, int xsize, int ysize) {
    /* libImaging handles */
    Imaging imDest, imSrc, imMask;
    /* cached blend properties */
    int src_has_alpha, mask_offset, mask_stride;
    /* source position */
    int sx, sy;
    /* iteration variables */
    unsigned int x, y, i;
    /* temporary calculation variables */
    int tmp1, tmp2, tmp3;
    /* integer [0, 255] version of overall_alpha */
    UINT8 overall_alpha_int = 255 * overall_alpha;
    
    /* short-circuit this whole thing if overall_alpha is zero */
    if (overall_alpha_int == 0)
        return dest;

    imDest = imaging_python_to_c(dest);
    imSrc = imaging_python_to_c(src);
    imMask = imaging_python_to_c(mask);

    if (!imDest || !imSrc || !imMask)
        return NULL;

    /* check the various image modes, make sure they make sense */
    if (strcmp(imDest->mode, "RGBA") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given destination image does not have mode \"RGBA\"");
        return NULL;
    }

    if (strcmp(imSrc->mode, "RGBA") != 0 && strcmp(imSrc->mode, "RGB") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given source image does not have mode \"RGBA\" or \"RGB\"");
        return NULL;
    }

    if (strcmp(imMask->mode, "RGBA") != 0 && strcmp(imMask->mode, "L") != 0) {
        PyErr_SetString(PyExc_ValueError,
                        "given mask image does not have mode \"RGBA\" or \"L\"");
        return NULL;
    }

    /* make sure mask size matches src size */
    if (imSrc->xsize != imMask->xsize || imSrc->ysize != imMask->ysize) {
        PyErr_SetString(PyExc_ValueError,
                        "mask and source image sizes do not match");
        return NULL;
    }

    /* set up flags for the src/mask type */
    src_has_alpha = (imSrc->pixelsize == 4 ? 1 : 0);
    /* how far into image the first alpha byte resides */
    mask_offset = (imMask->pixelsize == 4 ? 3 : 0);
    /* how many bytes to skip to get to the next alpha byte */
    mask_stride = imMask->pixelsize;

    /* setup source & destination vars */
    setup_source_destination(imSrc, imDest, &sx, &sy, &dx, &dy, &xsize, &ysize);

    /* check that there remains any blending to be done */
    if (xsize <= 0 || ysize <= 0) {
        /* nothing to do, return */
        return dest;
    }

    for (y = 0; y < ysize; y++) {
        UINT8 *out = (UINT8 *)imDest->image[dy + y] + dx * 4;
        UINT8 *outmask = (UINT8 *)imDest->image[dy + y] + dx * 4 + 3;
        UINT8 *in = (UINT8 *)imSrc->image[sy + y] + sx * (imSrc->pixelsize);
        UINT8 *inmask = (UINT8 *)imMask->image[sy + y] + sx * mask_stride + mask_offset;

        for (x = 0; x < xsize; x++) {
            UINT8 in_alpha;
            
            /* apply overall_alpha */
            if (overall_alpha_int != 255 && *inmask != 0) {
                in_alpha = MULDIV255(*inmask, overall_alpha_int, tmp1);
            } else {
                in_alpha = *inmask;
            }
            
            /* special cases */
            if (in_alpha == 255 || (*outmask == 0 && in_alpha > 0)) {
                *outmask = in_alpha;

                *out = *in;
                out++, in++;
                *out = *in;
                out++, in++;
                *out = *in;
                out++, in++;
            } else if (in_alpha == 0) {
                /* do nothing -- source is fully transparent */
                out += 3;
                in += 3;
            } else {
                /* general case */
                int alpha = in_alpha + MULDIV255(*outmask, 255 - in_alpha, tmp1);
                for (i = 0; i < 3; i++) {
                    /* general case */
                    *out = MULDIV255(*in, in_alpha, tmp1) +
                        MULDIV255(MULDIV255(*out, *outmask, tmp2), 255 - in_alpha, tmp3);
                    
                    *out = (*out * 255) / alpha;
                    out++, in++;
                }

                *outmask = alpha;
            }

            out++;
            if (src_has_alpha)
                in++;
            outmask += 4;
            inmask += mask_stride;
        }
    }

    return dest;
}