Fix part of #34233: bad alpha blending for 2D image painting. This is a very

old issue, the formulas here were never quite right, should all work ok now
with byte and float images.

Some differences:

* Colors with zero alpha from the background will never have an influence, so
  you don't get alpha fringes when painting over such areas. This does give
  hard edges when looking at the RGB channels alone, but there's no way to
  avoid that and fringes at the same time, same behavior as other painting apps.

* Add/Subtract/Multiply/Lighten/Darken now leave the alpha channel unchanged
  and work only the RGB channels, again same behavior as many other apps.

* Erase/Add alpha now compensates for premultiplied float images to keep the
  straight RGB colors the same.

Next: fix projection painting.
This commit is contained in:
Brecht Van Lommel 2013-04-27 12:51:23 +00:00
parent a580677801
commit 8f9150871c
Notes: blender-bot 2023-02-14 01:11:05 +01:00
Referenced by issue #86868, Image Editor "Erase Alpha" brush erases all channels of float images
14 changed files with 570 additions and 89 deletions

View File

@ -518,7 +518,9 @@ int BKE_brush_clone_image_delete(Brush *brush)
}
/* Generic texture sampler for 3D painting systems. point has to be either in
* region space mouse coordinates, or 3d world coordinates for 3D mapping */
* region space mouse coordinates, or 3d world coordinates for 3D mapping.
*
* rgba outputs straight alpha. */
float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
const float point[3],
float rgba[4], const int thread,
@ -755,7 +757,10 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
return intensity;
}
/* Brush Sampling for 2D brushes. when we unify the brush systems this will be necessarily a separate function */
/* Brush Sampling for 2D brushes. when we unify the brush systems this will be
* necessarily a separate function.
*
* rgba outputs straight alpha. */
float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4])
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@ -873,6 +878,11 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf
copy_v3_v3(dstf, brush_rgb);
dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
}
/* output premultiplied alpha image */
dstf[0] *= dstf[3];
dstf[1] *= dstf[3];
dstf[2] *= dstf[3];
}
}
}

View File

@ -27,8 +27,9 @@
#include <math.h>
#include <stdlib.h>
#include "BLI_math_color.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
#include "BKE_image.h"

View File

@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "BLI_edgehash.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"

View File

@ -126,7 +126,7 @@ void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b);
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
/***************** lift/gamma/gain / ASC-CDL conversion *****************/
/********* lift/gamma/gain / ASC-CDL conversion ***********/
void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power);

View File

@ -0,0 +1,71 @@
/*
* ***** 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.
*
* The Original Code is: some of this file.
*
* ***** END GPL LICENSE BLOCK *****
* */
#ifndef __BLI_MATH_COLOR_BLEND_H__
#define __BLI_MATH_COLOR_BLEND_H__
/** \file BLI_math_color.h
* \ingroup bli
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "BLI_math_inline.h"
/******************** Blending Modes **********************
* - byte function assume straight alpha
* - float functions assume premultiplied alpha
*/
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4]);
#if BLI_MATH_DO_INLINE
#include "intern/math_color_blend_inline.c"
#endif
#ifdef __cplusplus
}
#endif
#endif /* __BLI_MATH_COLOR_BLEND_H__ */

View File

@ -70,6 +70,7 @@ set(SRC
intern/math_base.c
intern/math_base_inline.c
intern/math_color.c
intern/math_color_blend_inline.c
intern/math_color_inline.c
intern/math_geom.c
intern/math_geom_inline.c
@ -128,6 +129,7 @@ set(SRC
BLI_math.h
BLI_math_base.h
BLI_math_color.h
BLI_math_color_blend.h
BLI_math_geom.h
BLI_math_inline.h
BLI_math_interp.h

View File

@ -35,7 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include "BLI_math.h"
#include "BLI_math_base.h"
/* copied from BLI_utildefines.h */
#ifdef __GNUC__

View File

@ -0,0 +1,413 @@
/*
* ***** 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.
*
* The Original Code is: some of this file.
*
* ***** END GPL LICENSE BLOCK *****
* */
/** \file blender/blenlib/intern/math_color_inline.c
* \ingroup bli
*/
#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
#ifndef __MATH_COLOR_BLEND_INLINE_C__
#define __MATH_COLOR_BLEND_INLINE_C__
/***************************** Color Blending ********************************
*
* - byte colors are assumed to be straight alpha
* - byte colors uses to do >>8 (same as /256) but actually should do /255,
* otherwise get quick darkening due to rounding
* - divide_round_i is also used to avoid darkening due to integers always
* rounding down
* - float colors are assumed to be premultiplied alpha
*/
/* straight alpha byte blending modes */
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight over operation */
const int t = src2[3];
const int mt = 255 - t;
int tmp[4];
tmp[0] = (mt * src1[3] * src1[0]) + (t * 255 * src2[0]);
tmp[1] = (mt * src1[3] * src1[1]) + (t * 255 * src2[1]);
tmp[2] = (mt * src1[3] * src1[2]) + (t * 255 * src2[2]);
tmp[3] = (mt * src1[3]) + (t * 255);
dst[0] = divide_round_i(tmp[0], tmp[3]);
dst[1] = divide_round_i(tmp[1], tmp[3]);
dst[2] = divide_round_i(tmp[2], tmp[3]);
dst[3] = divide_round_i(tmp[3], 255);
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight add operation */
const int t = src2[3];
int tmp[3];
tmp[0] = (src1[0] * 255) + (src2[0] * t);
tmp[1] = (src1[1] * 255) + (src2[1] * t);
tmp[2] = (src1[2] * 255) + (src2[2] * t);
dst[0] = min_ii(divide_round_i(tmp[0], 255), 255);
dst[1] = min_ii(divide_round_i(tmp[1], 255), 255);
dst[2] = min_ii(divide_round_i(tmp[2], 255), 255);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight sub operation */
const int t = src2[3];
int tmp[3];
tmp[0] = (src1[0] * 255) - (src2[0] * t);
tmp[1] = (src1[1] * 255) - (src2[1] * t);
tmp[2] = (src1[2] * 255) - (src2[2] * t);
dst[0] = max_ii(divide_round_i(tmp[0], 255), 0);
dst[1] = max_ii(divide_round_i(tmp[1], 255), 0);
dst[2] = max_ii(divide_round_i(tmp[2], 255), 0);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight multiply operation */
const int t = src2[3];
const int mt = 255 - t;
int tmp[3];
tmp[0] = (mt * src1[0] * 255) + (t * src1[0] * src2[0]);
tmp[1] = (mt * src1[1] * 255) + (t * src1[1] * src2[1]);
tmp[2] = (mt * src1[2] * 255) + (t * src1[2] * src2[2]);
dst[0] = divide_round_i(tmp[0], 255 * 255);
dst[1] = divide_round_i(tmp[1], 255 * 255);
dst[2] = divide_round_i(tmp[2], 255 * 255);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight lighten operation */
const int t = src2[3];
const int mt = 255 - t;
int tmp[3];
tmp[0] = (mt * src1[0]) + (t * max_ii(src1[0], src2[0]));
tmp[1] = (mt * src1[1]) + (t * max_ii(src1[1], src2[1]));
tmp[2] = (mt * src1[2]) + (t * max_ii(src1[2], src2[2]));
dst[0] = divide_round_i(tmp[0], 255);
dst[1] = divide_round_i(tmp[1], 255);
dst[2] = divide_round_i(tmp[2], 255);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight darken operation */
const int t = src2[3];
const int mt = 255 - t;
int tmp[3];
tmp[0] = (mt * src1[0]) + (t * min_ii(src1[0], src2[0]));
tmp[1] = (mt * src1[1]) + (t * min_ii(src1[1], src2[1]));
tmp[2] = (mt * src1[2]) + (t * min_ii(src1[2], src2[2]));
dst[0] = divide_round_i(tmp[0], 255);
dst[1] = divide_round_i(tmp[1], 255);
dst[2] = divide_round_i(tmp[2], 255);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight so just modify alpha channel */
const int t = src2[3];
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = max_ii(src1[3] - divide_round_i(t * src2[3], 255), 0);
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
{
if (src2[3] != 0) {
/* straight so just modify alpha channel */
const int t = src2[3];
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = min_ii(src1[3] + divide_round_i(t * src2[3], 255), 255);
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
/* premultiplied alpha float blending modes */
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* premul over operation */
const float t = src2[3];
const float mt = 1.0f - t;
dst[0] = mt * src1[0] + src2[0];
dst[1] = mt * src1[1] + src2[1];
dst[2] = mt * src1[2] + src2[2];
dst[3] = mt * src1[3] + t;
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* unpremul > add > premul, simplified */
dst[0] = src1[0] + src2[0] * src1[3];
dst[1] = src1[1] + src2[1] * src1[3];
dst[2] = src1[2] + src2[2] * src1[3];
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* unpremul > subtract > premul, simplified */
dst[0] = max_ff(src1[0] - src2[0] * src1[3], 0.0f);
dst[1] = max_ff(src1[1] - src2[1] * src1[3], 0.0f);
dst[2] = max_ff(src1[2] - src2[2] * src1[3], 0.0f);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* unpremul > multiply > premul, simplified */
const float t = src2[3];
const float mt = 1.0f - t;
dst[0] = mt * src1[0] + src1[0] * src2[0] * src1[3];
dst[1] = mt * src1[1] + src1[1] * src2[1] * src1[3];
dst[2] = mt * src1[2] + src1[2] * src2[2] * src1[3];
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* remap src2 to have same alpha as src1 premultiplied, take maximum of
* src1 and src2, then blend it with src1 */
const float t = src2[3];
const float mt = 1.0f - t;
const float map_alpha = src1[3]/src2[3];
dst[0] = mt * src1[0] + t * max_ff(src1[0], src2[0] * map_alpha);
dst[1] = mt * src1[1] + t * max_ff(src1[1], src2[1] * map_alpha);
dst[2] = mt * src1[2] + t * max_ff(src1[2], src2[2] * map_alpha);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f) {
/* remap src2 to have same alpha as src1 premultiplied, take minimum of
* src1 and src2, then blend it with src1 */
const float t = src2[3];
const float mt = 1.0f - t;
const float map_alpha = src1[3]/src2[3];
dst[0] = mt * src1[0] + t * min_ff(src1[0], src2[0] * map_alpha);
dst[1] = mt * src1[1] + t * min_ff(src1[1], src2[1] * map_alpha);
dst[2] = mt * src1[2] + t * min_ff(src1[2], src2[2] * map_alpha);
dst[3] = src1[3];
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f && src1[3] > 0.0f) {
/* subtract alpha and remap RGB channels to match */
const float alpha = max_ff(src1[3] - src2[3], 0.0f);
const float map_alpha = alpha/src1[3];
dst[0] *= map_alpha;
dst[1] *= map_alpha;
dst[2] *= map_alpha;
dst[3] = alpha;
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4])
{
if (src2[3] != 0.0f && src1[3] < 1.0f) {
/* add alpha and remap RGB channels to match */
const float alpha = min_ff(src1[3] + src2[3], 1.0f);
const float map_alpha = (src1[3] > 0.0f) ? alpha/src1[3] : 1.0f;
dst[0] *= map_alpha;
dst[1] *= map_alpha;
dst[2] *= map_alpha;
dst[3] = alpha;
}
else {
/* no op */
dst[0] = src1[0];
dst[1] = src1[1];
dst[2] = src1[2];
dst[3] = src1[3];
}
}
#endif /* __MATH_COLOR_BLEND_INLINE_C__ */

View File

@ -231,10 +231,11 @@ static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf
BKE_brush_sample_tex_2D(scene, brush, xy, tf);
}
bf[0] = tf[0] * mf[0];
bf[1] = tf[1] * mf[1];
bf[2] = tf[2] * mf[2];
bf[3] = tf[3] * mf[3];
/* output premultiplied float image, mf was already premultiplied */
bf[0] = tf[0] * tf[3] * mf[0];
bf[1] = tf[1] * tf[3] * mf[1];
bf[2] = tf[2] * tf[3] * mf[2];
bf[3] = tf[3] * tf[3] * mf[3];
}
}
}

View File

@ -3533,7 +3533,7 @@ typedef struct ProjectHandle {
struct ImagePool *pool;
} ProjectHandle;
static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
static void interpolate_color(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
{
/* this and other blending modes previously used >>8 instead of /255. both
* are not equivalent (>>8 is /256), and the former results in rounding
@ -3546,7 +3546,7 @@ static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], con
cp[3] = (mfac * cp1[3] + fac * cp2[3]) / 255;
}
static void blend_color_mix_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
static void interpolate_color_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
{
const float mfac = 1.0f - fac;
cp[0] = mfac * cp1[0] + fac * cp2[0];
@ -3584,7 +3584,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
{
if (ps->do_masking && mask < 1.0f) {
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend);
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
interpolate_color(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
}
else {
*projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * mask * 255), ps->blend);
@ -3595,7 +3595,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
{
if (ps->do_masking && mask < 1.0f) {
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
interpolate_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha * mask, ps->blend);
@ -3616,7 +3616,7 @@ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0)
return;
/* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255));
interpolate_color(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255));
BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
}
@ -3629,7 +3629,7 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl
return;
/* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask);
interpolate_color_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask);
BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
}
@ -3669,8 +3669,8 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
if (LIKELY(accum_tot != 0)) {
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
blend_color_mix_float(rgba, projPixel->pixel.f_pt, rgba, alpha);
if (mask < 1.0f) blend_color_mix_float(rgba, projPixel->origColor.f, rgba, mask);
interpolate_color_float(rgba, projPixel->pixel.f_pt, rgba, alpha);
if (mask < 1.0f) interpolate_color_float(rgba, projPixel->origColor.f, rgba, mask);
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@ -3706,8 +3706,8 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_ub, rgba);
blend_color_mix(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255));
if (mask != 1.0f) blend_color_mix(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255));
interpolate_color(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255));
if (mask != 1.0f) interpolate_color(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255));
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@ -3734,7 +3734,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
if (ps->do_masking && mask < 1.0f) {
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend);
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
interpolate_color(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
}
else {
*projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha * mask * 255), ps->blend);
@ -3756,7 +3756,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, flo
if (ps->do_masking && mask < 1.0f) {
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend);
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
interpolate_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha * mask, ps->blend);

View File

@ -171,7 +171,7 @@ typedef enum IMB_BlendMode {
unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac,
IMB_BlendMode mode);
void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac,
void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], float fac,
IMB_BlendMode mode);
void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,

View File

@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_vector.h"
#include "imbuf.h"
@ -48,7 +49,7 @@
/* blend modes */
static void blend_color_mix(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_mix(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
/* this and other blending modes previously used >>8 instead of /255. both
* are not equivalent (>>8 is /256), and the former results in rounding
@ -64,7 +65,7 @@ static void blend_color_mix(char cp[3], const char cp1[3], const char cp2[3], co
cp[3] = (temp > 255) ? 255 : temp;
}
static void blend_color_add(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_add(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
int temp;
@ -79,7 +80,7 @@ static void blend_color_add(char cp[3], const char cp1[3], const char cp2[3], co
cp[3] = (temp > 255) ? 255 : temp;
}
static void blend_color_sub(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_sub(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
int temp;
@ -94,7 +95,7 @@ static void blend_color_sub(char cp[3], const char cp1[3], const char cp2[3], co
cp[3] = (temp > 255) ? 255 : temp;
}
static void blend_color_mul(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_mul(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
int mfac = 255 - fac;
int temp;
@ -108,7 +109,7 @@ static void blend_color_mul(char cp[3], const char cp1[3], const char cp2[3], co
cp[3] = (temp > 255) ? 255 : temp;
}
static void blend_color_lighten(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_lighten(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
/* See if are lighter, if so mix, else don't do anything.
* if the paint col is darker then the original, then ignore */
@ -123,11 +124,11 @@ static void blend_color_lighten(char cp[3], const char cp1[3], const char cp2[3]
cp[3] = (temp > 255) ? 255 : temp;
}
else {
blend_color_mix(cp, cp1, cp2, fac);
imb_blend_color_mix(cp, cp1, cp2, fac);
}
}
static void blend_color_darken(char cp[3], const char cp1[3], const char cp2[3], const int fac)
static void imb_blend_color_darken(char cp[3], const char cp1[3], const char cp2[3], const int fac)
{
/* See if were darker, if so mix, else don't do anything.
* if the paint col is brighter then the original, then ignore */
@ -142,11 +143,11 @@ static void blend_color_darken(char cp[3], const char cp1[3], const char cp2[3],
cp[3] = (temp > 255) ? 255 : temp;
}
else {
blend_color_mix(cp, cp1, cp2, fac);
imb_blend_color_mix(cp, cp1, cp2, fac);
}
}
static void blend_color_erase_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
static void imb_blend_color_erase_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
{
int temp = cp1[3] - divide_round_i(fac * cp2[3], 255);
@ -156,7 +157,7 @@ static void blend_color_erase_alpha(char cp[4], const char cp1[4], const char cp
cp[3] = (temp < 0) ? 0 : temp;
}
static void blend_color_add_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
static void imb_blend_color_add_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
{
int temp = cp1[3] + divide_round_i(fac * cp2[3], 255);
@ -181,21 +182,21 @@ unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_
switch (mode) {
case IMB_BLEND_MIX:
blend_color_mix(cp, cp1, cp2, fac); break;
imb_blend_color_mix(cp, cp1, cp2, fac); break;
case IMB_BLEND_ADD:
blend_color_add(cp, cp1, cp2, fac); break;
imb_blend_color_add(cp, cp1, cp2, fac); break;
case IMB_BLEND_SUB:
blend_color_sub(cp, cp1, cp2, fac); break;
imb_blend_color_sub(cp, cp1, cp2, fac); break;
case IMB_BLEND_MUL:
blend_color_mul(cp, cp1, cp2, fac); break;
imb_blend_color_mul(cp, cp1, cp2, fac); break;
case IMB_BLEND_LIGHTEN:
blend_color_lighten(cp, cp1, cp2, fac); break;
imb_blend_color_lighten(cp, cp1, cp2, fac); break;
case IMB_BLEND_DARKEN:
blend_color_darken(cp, cp1, cp2, fac); break;
imb_blend_color_darken(cp, cp1, cp2, fac); break;
case IMB_BLEND_ERASE_ALPHA:
blend_color_erase_alpha(cp, cp1, cp2, fac); break;
imb_blend_color_erase_alpha(cp, cp1, cp2, fac); break;
case IMB_BLEND_ADD_ALPHA:
blend_color_add_alpha(cp, cp1, cp2, fac); break;
imb_blend_color_add_alpha(cp, cp1, cp2, fac); break;
default:
cp[0] = cp1[0];
cp[1] = cp1[1];
@ -207,7 +208,7 @@ unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_
return dst;
}
static void blend_color_mix_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_mix_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
float mfac = 1.0f - fac;
cp[0] = mfac * cp1[0] + fac * cp2[0];
@ -215,7 +216,7 @@ static void blend_color_mix_float(float cp[3], const float cp1[3], const float c
cp[2] = mfac * cp1[2] + fac * cp2[2];
}
static void blend_color_add_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_add_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
cp[0] = cp1[0] + fac * cp2[0];
cp[1] = cp1[1] + fac * cp2[1];
@ -226,7 +227,7 @@ static void blend_color_add_float(float cp[3], const float cp1[3], const float c
if (cp[2] > 1.0f) cp[2] = 1.0f;
}
static void blend_color_sub_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_sub_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
cp[0] = cp1[0] - fac * cp2[0];
cp[1] = cp1[1] - fac * cp2[1];
@ -237,7 +238,7 @@ static void blend_color_sub_float(float cp[3], const float cp1[3], const float c
if (cp[2] < 0.0f) cp[2] = 0.0f;
}
static void blend_color_mul_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_mul_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
float mfac = 1.0f - fac;
@ -246,7 +247,7 @@ static void blend_color_mul_float(float cp[3], const float cp1[3], const float c
cp[2] = mfac * cp1[2] + fac * (cp1[2] * cp2[2]);
}
static void blend_color_lighten_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_lighten_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
/* See if are lighter, if so mix, else don't do anything.
* if the pafloat col is darker then the original, then ignore */
@ -256,10 +257,10 @@ static void blend_color_lighten_float(float cp[3], const float cp1[3], const flo
cp[2] = cp1[2];
}
else
blend_color_mix_float(cp, cp1, cp2, fac);
imb_blend_color_mix_float(cp, cp1, cp2, fac);
}
static void blend_color_darken_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
static void imb_blend_color_darken_float(float cp[3], const float cp1[3], const float cp2[3], const float fac)
{
/* See if were darker, if so mix, else don't do anything.
* if the pafloat col is brighter then the original, then ignore */
@ -269,31 +270,10 @@ static void blend_color_darken_float(float cp[3], const float cp1[3], const floa
cp[2] = cp1[2];
}
else
blend_color_mix_float(cp, cp1, cp2, fac);
imb_blend_color_mix_float(cp, cp1, cp2, fac);
}
static void blend_color_erase_alpha_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
{
cp[0] = cp1[0];
cp[1] = cp1[1];
cp[2] = cp1[2];
cp[3] = (cp1[3] - fac * cp2[3]);
if (cp[3] < 0.0f) cp[3] = 0.0f;
}
static void blend_color_add_alpha_float(float cp[4], const float cp1[4], const float cp2[4], const float fac)
{
cp[0] = cp1[0];
cp[1] = cp1[1];
cp[2] = cp1[2];
cp[3] = (cp1[3] + fac * cp2[3]);
if (cp[3] < 0.0f) cp[3] = 0.0f;
if (cp[3] > 1.0f) cp[3] = 1.0f;
}
void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode)
void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], float fac, IMB_BlendMode mode)
{
if (fac == 0) {
dst[0] = src1[0];
@ -305,17 +285,17 @@ void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_
switch (mode) {
case IMB_BLEND_MIX:
blend_color_mix_float(dst, src1, src2, fac); break;
imb_blend_color_mix_float(dst, src1, src2, fac); break;
case IMB_BLEND_ADD:
blend_color_add_float(dst, src1, src2, fac); break;
imb_blend_color_add_float(dst, src1, src2, fac); break;
case IMB_BLEND_SUB:
blend_color_sub_float(dst, src1, src2, fac); break;
imb_blend_color_sub_float(dst, src1, src2, fac); break;
case IMB_BLEND_MUL:
blend_color_mul_float(dst, src1, src2, fac); break;
imb_blend_color_mul_float(dst, src1, src2, fac); break;
case IMB_BLEND_LIGHTEN:
blend_color_lighten_float(dst, src1, src2, fac); break;
imb_blend_color_lighten_float(dst, src1, src2, fac); break;
case IMB_BLEND_DARKEN:
blend_color_darken_float(dst, src1, src2, fac); break;
imb_blend_color_darken_float(dst, src1, src2, fac); break;
default:
dst[0] = src1[0];
dst[1] = src1[1];
@ -389,8 +369,8 @@ void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
IMB_BLEND_COPY);
}
typedef void (*IMB_blend_func)(char *dst, const char *src1, const char *src2, const int fac);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2, const float fac);
typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
@ -498,35 +478,35 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
else {
switch (mode) {
case IMB_BLEND_MIX:
func = blend_color_mix;
func = blend_color_mix_byte;
func_float = blend_color_mix_float;
break;
case IMB_BLEND_ADD:
func = blend_color_add;
func = blend_color_add_byte;
func_float = blend_color_add_float;
break;
case IMB_BLEND_SUB:
func = blend_color_sub;
func = blend_color_sub_byte;
func_float = blend_color_sub_float;
break;
case IMB_BLEND_MUL:
func = blend_color_mul;
func = blend_color_mul_byte;
func_float = blend_color_mul_float;
break;
case IMB_BLEND_LIGHTEN:
func = blend_color_lighten;
func = blend_color_lighten_byte;
func_float = blend_color_lighten_float;
break;
case IMB_BLEND_DARKEN:
func = blend_color_darken;
func = blend_color_darken_byte;
func_float = blend_color_darken_float;
break;
case IMB_BLEND_ERASE_ALPHA:
func = blend_color_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;
func = blend_color_add_alpha_byte;
func_float = blend_color_add_alpha_float;
break;
default:
@ -539,8 +519,8 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
dr = drect;
sr = srect;
for (x = width; x > 0; x--, dr++, sr++) {
if (((char *)sr)[3])
func((char *)dr, (char *)dr, (char *)sr, ((char *)sr)[3]);
if (((unsigned char *)sr)[3])
func((unsigned char *)dr, (unsigned char *)dr, (unsigned char *)sr);
}
drect += destskip;
@ -552,7 +532,7 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
srf = srectf;
for (x = width; x > 0; x--, drf += 4, srf += 4) {
if (srf[3] != 0)
func_float(drf, drf, srf, srf[3]);
func_float(drf, drf, srf);
}
drectf += destskip * 4;
srectf += srcskip * 4;

View File

@ -27,6 +27,7 @@
#include <stdlib.h>
#include "BLI_math_base.h"
#include "BLI_math_rotation.h"
#include "BLF_translation.h"

View File

@ -40,6 +40,7 @@
#include "BLI_array.h"
#include "BLI_math_base.h"
#include "BLI_math_rotation.h"
#include "BLI_utildefines.h"
#include "RNA_access.h"
#include "RNA_define.h"