void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, unsigned short *curvemask, unsigned short *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate) { unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, *or, *sr; float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf; unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; unsigned short *texmaskrect = texmask, *tmr; int do_float, do_char, srcskip, destskip, origskip, x; IMB_blend_func func = NULL; IMB_blend_func_float func_float = NULL; if (dbuf == NULL || obuf == NULL) return; imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &srcx, &srcy, &width, &height); if (width == 0 || height == 0) return; if (sbuf && sbuf->channels != 4) return; if (dbuf->channels != 4) return; do_char = (sbuf && sbuf->rect && dbuf->rect && obuf->rect); do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float); if (do_char) { drect = dbuf->rect + ((size_t)desty) * dbuf->x + destx; orect = obuf->rect + ((size_t)origy) * obuf->x + origx; } if (do_float) { drectf = dbuf->rect_float + (((size_t)desty) * dbuf->x + destx) * 4; orectf = obuf->rect_float + (((size_t)origy) * obuf->x + origx) * 4; } if (dmaskrect) dmaskrect += ((size_t)origy) * obuf->x + origx; destskip = dbuf->x; origskip = obuf->x; if (sbuf) { if (do_char) srect = sbuf->rect + ((size_t)srcy) * sbuf->x + srcx; if (do_float) srectf = sbuf->rect_float + (((size_t)srcy) * sbuf->x + srcx) * 4; srcskip = sbuf->x; if (cmaskrect) cmaskrect += ((size_t)srcy) * sbuf->x + srcx; if (texmaskrect) texmaskrect += ((size_t)srcy) * sbuf->x + srcx; } else { srect = drect; srectf = drectf; srcskip = destskip; } if (mode == IMB_BLEND_COPY) { /* copy */ for (; height > 0; height--) { if (do_char) { memcpy(drect, srect, width * sizeof(int)); drect += destskip; srect += srcskip; } if (do_float) { memcpy(drectf, srectf, width * sizeof(float) * 4); drectf += destskip * 4; srectf += srcskip * 4; } } } else if (mode == IMB_BLEND_COPY_RGB) { /* copy rgb only */ for (; height > 0; height--) { if (do_char) { dr = drect; sr = srect; for (x = width; x > 0; x--, dr++, sr++) { ((char *)dr)[0] = ((char *)sr)[0]; ((char *)dr)[1] = ((char *)sr)[1]; ((char *)dr)[2] = ((char *)sr)[2]; } drect += destskip; srect += srcskip; } if (do_float) { drf = drectf; srf = srectf; for (x = width; x > 0; x--, drf += 4, srf += 4) { float map_alpha = (srf[3] == 0.0f) ? drf[3] : drf[3] / srf[3]; drf[0] = srf[0] * map_alpha; drf[1] = srf[1] * map_alpha; drf[2] = srf[2] * map_alpha; } drectf += destskip * 4; srectf += srcskip * 4; } } } else if (mode == IMB_BLEND_COPY_ALPHA) { /* copy alpha only */ for (; height > 0; height--) { if (do_char) { dr = drect; sr = srect; for (x = width; x > 0; x--, dr++, sr++) ((char *)dr)[3] = ((char *)sr)[3]; drect += destskip; srect += srcskip; } if (do_float) { drf = drectf; srf = srectf; for (x = width; x > 0; x--, drf += 4, srf += 4) drf[3] = srf[3]; drectf += destskip * 4; srectf += srcskip * 4; } } } else { switch (mode) { case IMB_BLEND_MIX: case IMB_BLEND_INTERPOLATE: func = blend_color_mix_byte; func_float = blend_color_mix_float; break; case IMB_BLEND_ADD: func = blend_color_add_byte; func_float = blend_color_add_float; break; case IMB_BLEND_SUB: func = blend_color_sub_byte; func_float = blend_color_sub_float; break; case IMB_BLEND_MUL: func = blend_color_mul_byte; func_float = blend_color_mul_float; break; case IMB_BLEND_LIGHTEN: func = blend_color_lighten_byte; func_float = blend_color_lighten_float; break; case IMB_BLEND_DARKEN: func = blend_color_darken_byte; func_float = blend_color_darken_float; break; case IMB_BLEND_ERASE_ALPHA: func = blend_color_erase_alpha_byte; func_float = blend_color_erase_alpha_float; break; case IMB_BLEND_ADD_ALPHA: func = blend_color_add_alpha_byte; func_float = blend_color_add_alpha_float; break; case IMB_BLEND_OVERLAY: func = blend_color_overlay_byte; func_float = blend_color_overlay_float; break; case IMB_BLEND_HARDLIGHT: func = blend_color_hardlight_byte; func_float = blend_color_hardlight_float; break; case IMB_BLEND_COLORBURN: func = blend_color_burn_byte; func_float = blend_color_burn_float; break; case IMB_BLEND_LINEARBURN: func = blend_color_linearburn_byte; func_float = blend_color_linearburn_float; break; case IMB_BLEND_COLORDODGE: func = blend_color_dodge_byte; func_float = blend_color_dodge_float; break; case IMB_BLEND_SCREEN: func = blend_color_screen_byte; func_float = blend_color_screen_float; break; case IMB_BLEND_SOFTLIGHT: func = blend_color_softlight_byte; func_float = blend_color_softlight_float; break; case IMB_BLEND_PINLIGHT: func = blend_color_pinlight_byte; func_float = blend_color_pinlight_float; break; case IMB_BLEND_LINEARLIGHT: func = blend_color_linearlight_byte; func_float = blend_color_linearlight_float; break; case IMB_BLEND_VIVIDLIGHT: func = blend_color_vividlight_byte; func_float = blend_color_vividlight_float; break; case IMB_BLEND_DIFFERENCE: func = blend_color_difference_byte; func_float = blend_color_difference_float; break; case IMB_BLEND_EXCLUSION: func = blend_color_exclusion_byte; func_float = blend_color_exclusion_float; break; case IMB_BLEND_COLOR: func = blend_color_color_byte; func_float = blend_color_color_float; break; case IMB_BLEND_HUE: func = blend_color_hue_byte; func_float = blend_color_hue_float; break; case IMB_BLEND_SATURATION: func = blend_color_saturation_byte; func_float = blend_color_saturation_float; break; case IMB_BLEND_LUMINOSITY: func = blend_color_luminosity_byte; func_float = blend_color_luminosity_float; break; default: break; } /* blend */ for (; height > 0; height--) { if (do_char) { dr = drect; or = orect; sr = srect; if (cmaskrect) { /* mask accumulation for painting */ cmr = cmaskrect; tmr = texmaskrect; /* destination mask present, do max alpha masking */ if (dmaskrect) { dmr = dmaskrect; for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, cmr++) { unsigned char *src = (unsigned char *)sr; float mask_lim = mask_max * (*cmr); if (texmaskrect) mask_lim *= ((*tmr++) / 65535.0f); if (src[3] && mask_lim) { float mask; if (accumulate) mask = *dmr + mask_lim; else mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); mask = min_ff(mask, 65535.0); if (mask > *dmr) { unsigned char mask_src[4]; *dmr = mask; mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; if (mode == IMB_BLEND_INTERPOLATE) { mask_src[3] = src[3]; blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); } else { mask_src[3] = divide_round_i(src[3] * mask, 65535); func((unsigned char *)dr, (unsigned char *)or, mask_src); } } } } dmaskrect += origskip; } /* no destination mask buffer, do regular blend with masktexture if present */ else { for (x = width; x > 0; x--, dr++, or++, sr++, cmr++) { unsigned char *src = (unsigned char *)sr; float mask = (float)mask_max * ((float)(*cmr)); if (texmaskrect) mask *= ((float)(*tmr++) / 65535.0f); mask = min_ff(mask, 65535.0); if (src[3] && (mask > 0.0f)) { unsigned char mask_src[4]; mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; if (mode == IMB_BLEND_INTERPOLATE) { mask_src[3] = src[3]; blend_color_interpolate_byte((unsigned char *)dr, (unsigned char *)or, mask_src, mask / 65535.0f); } else { mask_src[3] = divide_round_i(src[3] * mask, 65535); func((unsigned char *)dr, (unsigned char *)or, mask_src); } } } } cmaskrect += srcskip; if (texmaskrect) texmaskrect += srcskip; } else { /* regular blending */ for (x = width; x > 0; x--, dr++, or++, sr++) { if (((unsigned char *)sr)[3]) func((unsigned char *)dr, (unsigned char *)or, (unsigned char *)sr); } } drect += destskip; orect += origskip; srect += srcskip; } if (do_float) { drf = drectf; orf = orectf; srf = srectf; if (cmaskrect) { /* mask accumulation for painting */ cmr = cmaskrect; tmr = texmaskrect; /* destination mask present, do max alpha masking */ if (dmaskrect) { dmr = dmaskrect; for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, cmr++) { float mask_lim = mask_max * (*cmr); if (texmaskrect) mask_lim *= ((*tmr++) / 65535.0f); if (srf[3] && mask_lim) { float mask; if (accumulate) mask = min_ff(*dmr + mask_lim, 65535.0); else mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); mask = min_ff(mask, 65535.0); if (mask > *dmr) { *dmr = mask; if (mode == IMB_BLEND_INTERPOLATE) { blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); } else { float mask_srf[4]; mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); func_float(drf, orf, mask_srf); } } } } dmaskrect += origskip; } /* no destination mask buffer, do regular blend with masktexture if present */ else { for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, cmr++) { float mask = (float)mask_max * ((float)(*cmr)); if (texmaskrect) mask *= ((float)(*tmr++) / 65535.0f); mask = min_ff(mask, 65535.0); if (srf[3] && (mask > 0.0f)) { if (mode == IMB_BLEND_INTERPOLATE) { blend_color_interpolate_float(drf, orf, srf, mask / 65535.0f); } else { float mask_srf[4]; mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); func_float(drf, orf, mask_srf); } } } } cmaskrect += srcskip; if (texmaskrect) texmaskrect += srcskip; } else { /* regular blending */ for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) { if (srf[3] != 0) func_float(drf, orf, srf); } } drectf += destskip * 4; orectf += origskip * 4; srectf += srcskip * 4; } } } }
void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, unsigned short *smask, unsigned short mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, short lock_alpha) { unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr; float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf; unsigned short *smaskrect = smask, *smr; unsigned short *dmaskrect = dmask, *dmr; int do_float, do_char, srcskip, destskip, origskip, x; IMB_blend_func func = NULL; IMB_blend_func_float func_float = NULL; if (dbuf == NULL || obuf == NULL) return; imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &srcx, &srcy, &width, &height); if (width == 0 || height == 0) return; if (sbuf && sbuf->channels != 4) return; if (dbuf->channels != 4) return; do_char = (sbuf && sbuf->rect && dbuf->rect && obuf->rect); do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float); if (do_char) { drect = dbuf->rect + desty * dbuf->x + destx; orect = obuf->rect + origy * obuf->x + origx; } if (do_float) { drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4; orectf = obuf->rect_float + (origy * obuf->x + origx) * 4; } if (dmaskrect) dmaskrect += origy * obuf->x + origx; destskip = dbuf->x; origskip = obuf->x; if (sbuf) { if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx; if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4; srcskip = sbuf->x; if (smaskrect) smaskrect += srcy * sbuf->x + srcx; } else { srect = drect; srectf = drectf; srcskip = destskip; } if (mode == IMB_BLEND_COPY) { /* copy */ for (; height > 0; height--) { if (do_char) { memcpy(drect, srect, width * sizeof(int)); drect += destskip; srect += srcskip; } if (do_float) { memcpy(drectf, srectf, width * sizeof(float) * 4); drectf += destskip * 4; srectf += srcskip * 4; } } } else if (mode == IMB_BLEND_COPY_RGB) { /* copy rgb only */ for (; height > 0; height--) { if (do_char) { dr = drect; sr = srect; for (x = width; x > 0; x--, dr++, sr++) { ((char *)dr)[0] = ((char *)sr)[0]; ((char *)dr)[1] = ((char *)sr)[1]; ((char *)dr)[2] = ((char *)sr)[2]; } drect += destskip; srect += srcskip; } if (do_float) { drf = drectf; srf = srectf; for (x = width; x > 0; x--, drf += 4, srf += 4) { float map_alpha = (srf[3] == 0.0f)? drf[3] : drf[3] / srf[3]; drf[0] = srf[0] * map_alpha; drf[1] = srf[1] * map_alpha; drf[2] = srf[2] * map_alpha; } drectf += destskip * 4; srectf += srcskip * 4; } } } else if (mode == IMB_BLEND_COPY_ALPHA) { /* copy alpha only */ for (; height > 0; height--) { if (do_char) { dr = drect; sr = srect; for (x = width; x > 0; x--, dr++, sr++) ((char *)dr)[3] = ((char *)sr)[3]; drect += destskip; srect += srcskip; } if (do_float) { drf = drectf; srf = srectf; for (x = width; x > 0; x--, drf += 4, srf += 4) drf[3] = srf[3]; drectf += destskip * 4; srectf += srcskip * 4; } } } else { switch (mode) { case IMB_BLEND_MIX: func = blend_color_mix_byte; func_float = blend_color_mix_float; break; case IMB_BLEND_ADD: func = blend_color_add_byte; func_float = blend_color_add_float; break; case IMB_BLEND_SUB: func = blend_color_sub_byte; func_float = blend_color_sub_float; break; case IMB_BLEND_MUL: func = blend_color_mul_byte; func_float = blend_color_mul_float; break; case IMB_BLEND_LIGHTEN: func = blend_color_lighten_byte; func_float = blend_color_lighten_float; break; case IMB_BLEND_DARKEN: func = blend_color_darken_byte; func_float = blend_color_darken_float; break; case IMB_BLEND_ERASE_ALPHA: func = blend_color_erase_alpha_byte; func_float = blend_color_erase_alpha_float; break; case IMB_BLEND_ADD_ALPHA: func = blend_color_add_alpha_byte; func_float = blend_color_add_alpha_float; break; default: break; } /* blend */ for (; height > 0; height--) { if (do_char) { dr = drect; or = orect; sr = srect; if (dmaskrect && smaskrect) { /* mask accumulation for painting */ dmr = dmaskrect; smr = smaskrect; for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, smr++) { unsigned char *src = (unsigned char *)sr; if (!((lock_alpha & IMA_LAYER_LOCK_ALPHA) && (pixel_is_transparent((unsigned char *)or)))) { if (src[3] && *smr) { unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); if (mask > *dmr) { unsigned char mask_src[4]; *dmr = mask; mask_src[0] = src[0]; mask_src[1] = src[1]; mask_src[2] = src[2]; mask_src[3] = divide_round_i(src[3] * mask, 65535); func((unsigned char *)dr, (unsigned char *)or, mask_src); } } } } dmaskrect += origskip; smaskrect += srcskip; } else { /* regular blending */ for (x = width; x > 0; x--, dr++, or++, sr++) { if (((unsigned char *)sr)[3]) func((unsigned char *)dr, (unsigned char *)or, (unsigned char *)sr); } } drect += destskip; orect += origskip; srect += srcskip; } if (do_float) { drf = drectf; orf = orectf; srf = srectf; if (dmaskrect && smaskrect) { /* mask accumulation for painting */ dmr = dmaskrect; smr = smaskrect; for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, smr++) { if (srf[3] != 0 && *smr) { unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); if (mask > *dmr) { float mask_srf[4]; *dmr = mask; mul_v4_v4fl(mask_srf, srf, mask * (1.0f / 65535.0f)); func_float(drf, orf, mask_srf); } } } dmaskrect += origskip; smaskrect += srcskip; } else { /* regular blending */ for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) { if (srf[3] != 0) func_float(drf, orf, srf); } } drectf += destskip * 4; orectf += origskip * 4; srectf += srcskip * 4; } } } }