diff options
Diffstat (limited to 'source/blender/render/intern/source/pixelblending.c')
-rw-r--r-- | source/blender/render/intern/source/pixelblending.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c new file mode 100644 index 00000000000..c7cfe765f5b --- /dev/null +++ b/source/blender/render/intern/source/pixelblending.c @@ -0,0 +1,400 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, 2004-2006 Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/pixelblending.c + * \ingroup render + * + * Functions to blend pixels with or without alpha, in various formats + * nzc - June 2000 + */ + + +#include <math.h> +#include <string.h> + +/* global includes */ + +/* own includes */ +#include "render_types.h" +#include "pixelblending.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +/* ------------------------------------------------------------------------- */ +/* Debug/behavior defines */ +/* if defined: alpha blending with floats clips color, as with shorts */ +/* #define RE_FLOAT_COLOR_CLIPPING */ +/* if defined: alpha values are clipped */ +/* For now, we just keep alpha clipping. We run into thresholding and */ +/* blending difficulties otherwise. Be careful here. */ +#define RE_ALPHA_CLIPPING + + + +/* Threshold for a 'full' pixel: pixels with alpha above this level are */ +/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */ +#define RE_FULL_COLOR_FLOAT 0.9998f +/* Threshold for an 'empty' pixel: pixels with alpha above this level are */ +/* considered completely transparent. This is the decimal value */ +/* for 0x000F / 0xFFFF */ +#define RE_EMPTY_COLOR_FLOAT 0.0002f + + +/* ------------------------------------------------------------------------- */ + +void addAlphaOverFloat(float dest[4], const float source[4]) +{ + /* d = s + (1-alpha_s)d*/ + float mul; + + mul = 1.0f - source[3]; + + dest[0] = (mul * dest[0]) + source[0]; + dest[1] = (mul * dest[1]) + source[1]; + dest[2] = (mul * dest[2]) + source[2]; + dest[3] = (mul * dest[3]) + source[3]; + +} + + +/* ------------------------------------------------------------------------- */ + +void addAlphaUnderFloat(float dest[4], const float source[4]) +{ + float mul; + + mul = 1.0f - dest[3]; + + dest[0] += (mul * source[0]); + dest[1] += (mul * source[1]); + dest[2] += (mul * source[2]); + dest[3] += (mul * source[3]); +} + + +/* ------------------------------------------------------------------------- */ +void addalphaAddfacFloat(float dest[4], const float source[4], char addfac) +{ + float m; /* weiging factor of destination */ + float c; /* intermediate color */ + + /* Addfac is a number between 0 and 1: rescale */ + /* final target is to diminish the influence of dest when addfac rises */ + m = 1.0f - (source[3] * ((255 - addfac) / 255.0f)); + + /* blend colors*/ + c = (m * dest[0]) + source[0]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[0] = c; + + c = (m * dest[1]) + source[1]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[1] = c; + + c = (m * dest[2]) + source[2]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[2] = c; + + c = (m * dest[3]) + source[3]; +#ifdef RE_ALPHA_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[3] = c; + +} + + +/* ------------------------------------------------------------------------- */ + +/* filtered adding to scanlines */ +void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w) +{ + /* calc the value of mask */ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + float *rb1, *rb2, *rb3; + float val, r, g, b, al; + unsigned int a, maskand, maskshift; + int j; + + r = col[0]; + g = col[1]; + b = col[2]; + al = col[3]; + + rb2 = rowbuf - 4; + rb3 = rb2 - 4 * row_w; + rb1 = rb2 + 4 * row_w; + + maskand = (mask & 255); + maskshift = (mask >> 8); + + for (j = 2; j >= 0; j--) { + + a = j; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb1[0] += val * r; + rb1[1] += val * g; + rb1[2] += val * b; + rb1[3] += val * al; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb2[0] += val * r; + rb2[1] += val * g; + rb2[2] += val * b; + rb2[3] += val * al; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb3[0] += val * r; + rb3[1] += val * g; + rb3[2] += val * b; + rb3[3] += val * al; + } + + rb1 += 4; + rb2 += 4; + rb3 += 4; + } +} + + +void mask_array(unsigned int mask, float filt[3][3]) +{ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + unsigned int maskand = (mask & 255); + unsigned int maskshift = (mask >> 8); + int a, j; + + for (j = 2; j >= 0; j--) { + + a = j; + + filt[2][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + + a += 3; + + filt[1][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + + a += 3; + + filt[0][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + } +} + + +/** + * Index ordering, scanline based: + * + * <pre> + * --- --- --- + * | 2,0 | 2,1 | 2,2 | + * --- --- --- + * | 1,0 | 1,1 | 1,2 | + * --- --- --- + * | 0,0 | 0,1 | 0,2 | + * --- --- --- + * </pre> + */ + +void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask) +{ + float *fpoin[3][3]; + float val, r, g, b, al, lfilt[3][3]; + + r = col[0]; + g = col[1]; + b = col[2]; + al = col[3]; + + memcpy(lfilt, filt, sizeof(lfilt)); + + fpoin[0][1] = rowbuf - 4 * row_stride; + fpoin[1][1] = rowbuf; + fpoin[2][1] = rowbuf + 4 * row_stride; + + fpoin[0][0] = fpoin[0][1] - 4; + fpoin[1][0] = fpoin[1][1] - 4; + fpoin[2][0] = fpoin[2][1] - 4; + + fpoin[0][2] = fpoin[0][1] + 4; + fpoin[1][2] = fpoin[1][1] + 4; + fpoin[2][2] = fpoin[2][1] + 4; + + /* limit filtering to withing a mask for border rendering, so pixels don't + * leak outside of the border */ + if (y <= mask->ymin) { + fpoin[0][0] = fpoin[1][0]; + fpoin[0][1] = fpoin[1][1]; + fpoin[0][2] = fpoin[1][2]; + /* filter needs the opposite value yes! */ + lfilt[0][0] = filt[2][0]; + lfilt[0][1] = filt[2][1]; + lfilt[0][2] = filt[2][2]; + } + else if (y >= mask->ymax - 1) { + fpoin[2][0] = fpoin[1][0]; + fpoin[2][1] = fpoin[1][1]; + fpoin[2][2] = fpoin[1][2]; + + lfilt[2][0] = filt[0][0]; + lfilt[2][1] = filt[0][1]; + lfilt[2][2] = filt[0][2]; + } + + if (x <= mask->xmin) { + fpoin[2][0] = fpoin[2][1]; + fpoin[1][0] = fpoin[1][1]; + fpoin[0][0] = fpoin[0][1]; + + lfilt[2][0] = filt[2][2]; + lfilt[1][0] = filt[1][2]; + lfilt[0][0] = filt[0][2]; + } + else if (x >= mask->xmax - 1) { + fpoin[2][2] = fpoin[2][1]; + fpoin[1][2] = fpoin[1][1]; + fpoin[0][2] = fpoin[0][1]; + + lfilt[2][2] = filt[2][0]; + lfilt[1][2] = filt[1][0]; + lfilt[0][2] = filt[0][0]; + } + + + /* loop unroll */ +#define MASKFILT(i, j) \ + val = lfilt[i][j]; \ + if (val != 0.0f) { \ + float *fp = fpoin[i][j]; \ + fp[0] += val * r; \ + fp[1] += val * g; \ + fp[2] += val * b; \ + fp[3] += val * al; \ + } (void)0 + + MASKFILT(0, 0); + MASKFILT(0, 1); + MASKFILT(0, 2); + MASKFILT(1, 0); + MASKFILT(1, 1); + MASKFILT(1, 2); + MASKFILT(2, 0); + MASKFILT(2, 1); + MASKFILT(2, 2); + +#undef MASKFILT +} + +void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize) +{ + /* calc the value of mask */ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + float *rb1, *rb2, *rb3; + float val; + unsigned int a, maskand, maskshift; + int i, j; + + rb2 = rowbuf - pixsize; + rb3 = rb2 - pixsize * row_w; + rb1 = rb2 + pixsize * row_w; + + maskand = (mask & 255); + maskshift = (mask >> 8); + + for (j = 2; j >= 0; j--) { + + a = j; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb1[i] += val * in[i]; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb2[i] += val * in[i]; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb3[i] += val * in[i]; + } + + rb1 += pixsize; + rb2 += pixsize; + rb3 += pixsize; + } +} + +/* ------------------------------------------------------------------------- */ +void addalphaAddFloat(float dest[4], const float source[4]) +{ + + /* Makes me wonder whether this is required... */ + if (dest[3] < RE_EMPTY_COLOR_FLOAT) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } + + /* no clipping! */ + dest[0] = dest[0] + source[0]; + dest[1] = dest[1] + source[1]; + dest[2] = dest[2] + source[2]; + dest[3] = dest[3] + source[3]; + +} + + +/* ---------------------------------------------------------------------------- */ |