[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [56293] trunk/blender/source/blender: Fix part of #34640: colors darkening when using the vertex paint blur tool .

Brecht Van Lommel brechtvanlommel at pandora.be
Thu Apr 25 16:16:22 CEST 2013


Revision: 56293
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=56293
Author:   blendix
Date:     2013-04-25 14:16:22 +0000 (Thu, 25 Apr 2013)
Log Message:
-----------
Fix part of #34640: colors darkening when using the vertex paint blur tool.

The problem was that vertex colors only have 8 bits of precision, and integer
division always rounds down, so after some color blending iterations everything
gets darker. Instead use integer division that behaves like round() instead of
floor() for blending operations.

Modified Paths:
--------------
    trunk/blender/source/blender/blenlib/BLI_math_base.h
    trunk/blender/source/blender/blenlib/intern/math_base_inline.c
    trunk/blender/source/blender/editors/sculpt_paint/paint_vertex.c
    trunk/blender/source/blender/imbuf/intern/rectop.c

Modified: trunk/blender/source/blender/blenlib/BLI_math_base.h
===================================================================
--- trunk/blender/source/blender/blenlib/BLI_math_base.h	2013-04-25 13:28:32 UTC (rev 56292)
+++ trunk/blender/source/blender/blenlib/BLI_math_base.h	2013-04-25 14:16:22 UTC (rev 56293)
@@ -213,6 +213,8 @@
 MINLINE int power_of_2_max_i(int n);
 MINLINE int power_of_2_min_i(int n);
 
+MINLINE int divide_round_i(int a, int b);
+
 MINLINE float shell_angle_to_dist(const float angle);
 
 #if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)

Modified: trunk/blender/source/blender/blenlib/intern/math_base_inline.c
===================================================================
--- trunk/blender/source/blender/blenlib/intern/math_base_inline.c	2013-04-25 13:28:32 UTC (rev 56292)
+++ trunk/blender/source/blender/blenlib/intern/math_base_inline.c	2013-04-25 14:16:22 UTC (rev 56293)
@@ -145,6 +145,13 @@
 	return n;
 }
 
+/* integer division that rounds 0.5 up, particularly useful for color blending
+ * with integers, to avoid gradual darkening when rounding down */
+MINLINE int divide_round_i(int a, int b)
+{
+	return (2*a + b)/(2*b);
+}
+
 MINLINE unsigned int highest_order_bit_i(unsigned int n)
 {
 	n |= (n >>  1);

Modified: trunk/blender/source/blender/editors/sculpt_paint/paint_vertex.c
===================================================================
--- trunk/blender/source/blender/editors/sculpt_paint/paint_vertex.c	2013-04-25 13:28:32 UTC (rev 56292)
+++ trunk/blender/source/blender/editors/sculpt_paint/paint_vertex.c	2013-04-25 14:16:22 UTC (rev 56293)
@@ -256,9 +256,9 @@
 	scol = scolmain;
 	while (a--) {
 		if (scol[0] > 1) {
-			scol[1] /= scol[0];
-			scol[2] /= scol[0];
-			scol[3] /= scol[0];
+			scol[1] = divide_round_i(scol[1], scol[0]);
+			scol[2] = divide_round_i(scol[2], scol[0]);
+			scol[3] = divide_round_i(scol[3], scol[0]);
 		}
 		scol += 4;
 	}
@@ -287,7 +287,7 @@
 {
 	const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
 	MPoly *mp;
-	float (*scol)[4];
+	int (*scol)[4];
 	int i, j, has_shared = 0;
 
 	/* if no mloopcol: do not do */
@@ -295,7 +295,7 @@
 
 	if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
 
-	scol = MEM_callocN(sizeof(float) * me->totvert * 5, "scol");
+	scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
 
 	for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
 		if ((use_face_sel == FALSE) || (mp->flag & ME_FACE_SEL)) {
@@ -305,7 +305,7 @@
 				scol[ml->v][0] += lcol->r;
 				scol[ml->v][1] += lcol->g;
 				scol[ml->v][2] += lcol->b;
-				scol[ml->v][3] += 1.0f;
+				scol[ml->v][3] += 1;
 				has_shared = 1;
 			}
 		}
@@ -313,8 +313,10 @@
 
 	if (has_shared) {
 		for (i = 0; i < me->totvert; i++) {
-			if (scol[i][3] != 0.0f) {
-				mul_v3_fl(scol[i], 1.0f / scol[i][3]);
+			if (scol[i][3] != 0) {
+				scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
+				scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
+				scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
 			}
 		}
 
@@ -613,9 +615,9 @@
 	cp2 = (unsigned char *)&col2;
 	cp  = (unsigned char *)&col;
 
-	cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
-	cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
-	cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+	cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
+	cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
+	cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
 	cp[3] = 255;
 
 	return col;
@@ -635,11 +637,11 @@
 	cp2 = (unsigned char *)&col2;
 	cp  = (unsigned char *)&col;
 
-	temp = cp1[0] + ((fac * cp2[0]) / 255);
+	temp = cp1[0] + divide_round_i((fac * cp2[0]), 255);
 	cp[0] = (temp > 254) ? 255 : temp;
-	temp = cp1[1] + ((fac * cp2[1]) / 255);
+	temp = cp1[1] + divide_round_i((fac * cp2[1]), 255);
 	cp[1] = (temp > 254) ? 255 : temp;
-	temp = cp1[2] + ((fac * cp2[2]) / 255);
+	temp = cp1[2] + divide_round_i((fac * cp2[2]), 255);
 	cp[2] = (temp > 254) ? 255 : temp;
 	cp[3] = 255;
 	
@@ -660,11 +662,11 @@
 	cp2 = (unsigned char *)&col2;
 	cp  = (unsigned char *)&col;
 
-	temp = cp1[0] - ((fac * cp2[0]) / 255);
+	temp = cp1[0] - divide_round_i((fac * cp2[0]), 255);
 	cp[0] = (temp < 0) ? 0 : temp;
-	temp = cp1[1] - ((fac * cp2[1]) / 255);
+	temp = cp1[1] - divide_round_i((fac * cp2[1]), 255);
 	cp[1] = (temp < 0) ? 0 : temp;
-	temp = cp1[2] - ((fac * cp2[2]) / 255);
+	temp = cp1[2] - divide_round_i((fac * cp2[2]), 255);
 	cp[2] = (temp < 0) ? 0 : temp;
 	cp[3] = 255;
 
@@ -688,9 +690,9 @@
 	cp  = (unsigned char *)&col;
 
 	/* first mul, then blend the fac */
-	cp[0] = (mfac * cp1[0] + fac * ((cp2[0] * cp1[0]) / 255)) / 255;
-	cp[1] = (mfac * cp1[1] + fac * ((cp2[1] * cp1[1]) / 255)) / 255;
-	cp[2] = (mfac * cp1[2] + fac * ((cp2[2] * cp1[2]) / 255)) / 255;
+	cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255*255);
+	cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255*255);
+	cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255*255);
 	cp[3] = 255;
 
 	return col;
@@ -721,9 +723,9 @@
 		return col1;
 	}
 
-	cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
-	cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
-	cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+	cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255);
+	cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255);
+	cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255);
 	cp[3] = 255;
 
 	return col;
@@ -754,9 +756,9 @@
 		return col1;
 	}
 
-	cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
-	cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
-	cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+	cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
+	cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
+	cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
 	cp[3] = 255;
 	return col;
 }
@@ -2790,6 +2792,7 @@
 	unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart;
 	float alpha;
 	int i, j;
+	int totloop = mpoly->totloop;
 
 	int brush_alpha_pressure_i = (int)(brush_alpha_pressure * 255.0f);
 
@@ -2798,7 +2801,7 @@
 		unsigned int tcol;
 		char *col;
 
-		for (j = 0; j < mpoly->totloop; j++) {
+		for (j = 0; j < totloop; j++) {
 			col = (char *)(lcol + j);
 			blend[0] += col[0];
 			blend[1] += col[1];
@@ -2806,10 +2809,10 @@
 			blend[3] += col[3];
 		}
 
-		blend[0] /= mpoly->totloop;
-		blend[1] /= mpoly->totloop;
-		blend[2] /= mpoly->totloop;
-		blend[3] /= mpoly->totloop;
+		blend[0] = divide_round_i(blend[0], totloop);
+		blend[1] = divide_round_i(blend[1], totloop);
+		blend[2] = divide_round_i(blend[2], totloop);
+		blend[3] = divide_round_i(blend[3], totloop);
 		col = (char *)&tcol;
 		col[0] = blend[0];
 		col[1] = blend[1];
@@ -2820,7 +2823,7 @@
 	}
 
 	ml = me->mloop + mpoly->loopstart;
-	for (i = 0; i < mpoly->totloop; i++, ml++) {
+	for (i = 0; i < totloop; i++, ml++) {
 		float rgba[4];
 		unsigned int paintcol;
 		alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
@@ -2851,7 +2854,7 @@
 
 			ml = me->mloop + mpoly->loopstart;
 			mlc = me->mloopcol + mpoly->loopstart;
-			for (j = 0; j < mpoly->totloop; j++, ml++, mlc++) {
+			for (j = 0; j < totloop; j++, ml++, mlc++) {
 				if (ml->v == mf->v1) {
 					MESH_MLOOPCOL_TO_MCOL(mlc, mc + 0);
 				}

Modified: trunk/blender/source/blender/imbuf/intern/rectop.c
===================================================================
--- trunk/blender/source/blender/imbuf/intern/rectop.c	2013-04-25 13:28:32 UTC (rev 56292)
+++ trunk/blender/source/blender/imbuf/intern/rectop.c	2013-04-25 14:16:22 UTC (rev 56293)
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 
 #include "BLI_utildefines.h"
+#include "BLI_math_base.h"
 #include "BLI_math_color.h"
 #include "BLI_math_vector.h"
 
@@ -54,20 +55,20 @@
 	 * errors that can turn colors black fast after repeated blending */
 	const int mfac = 255 - fac;
 
-	cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255;
-	cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255;
-	cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255;
+	cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
+	cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
+	cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
 }
 
 static void blend_color_add(char cp[3], const char cp1[3], const char cp2[3], const int fac)
 {
 	int temp;
 
-	temp = cp1[0] + ((fac * cp2[0]) / 255);
+	temp = cp1[0] + divide_round_i(fac * cp2[0], 255);
 	if (temp > 254) cp[0] = 255; else cp[0] = temp;
-	temp = cp1[1] + ((fac * cp2[1]) / 255);
+	temp = cp1[1] + divide_round_i(fac * cp2[1] , 255);
 	if (temp > 254) cp[1] = 255; else cp[1] = temp;
-	temp = cp1[2] + ((fac * cp2[2]) / 255);
+	temp = cp1[2] + divide_round_i(fac * cp2[2] , 255);
 	if (temp > 254) cp[2] = 255; else cp[2] = temp;
 }
 
@@ -75,11 +76,11 @@
 {
 	int temp;
 
-	temp = cp1[0] - ((fac * cp2[0]) / 255);
+	temp = cp1[0] - divide_round_i(fac * cp2[0], 255);
 	if (temp < 0) cp[0] = 0; else cp[0] = temp;
-	temp = cp1[1] - ((fac * cp2[1]) / 255);
+	temp = cp1[1] - divide_round_i(fac * cp2[1], 255);
 	if (temp < 0) cp[1] = 0; else cp[1] = temp;
-	temp = cp1[2] - ((fac * cp2[2]) / 255);
+	temp = cp1[2] - divide_round_i(fac * cp2[2], 255);
 	if (temp < 0) cp[2] = 0; else cp[2] = temp;
 }
 
@@ -88,9 +89,9 @@
 	int mfac = 255 - fac;
 	
 	/* first mul, then blend the fac */
-	cp[0] = (mfac * cp1[0] + fac * ((cp1[0] * cp2[0]) / 255)) / 255;
-	cp[1] = (mfac * cp1[1] + fac * ((cp1[1] * cp2[1]) / 255)) / 255;
-	cp[2] = (mfac * cp1[2] + fac * ((cp1[2] * cp2[2]) / 255)) / 255;
+	cp[0] = divide_round_i((mfac * cp1[0] * 255) + (fac * cp1[0] * cp2[0]), 255*255);
+	cp[1] = divide_round_i((mfac * cp1[1] * 255) + (fac * cp1[1] * cp2[1]), 255*255);
+	cp[2] = divide_round_i((mfac * cp1[2] * 255) + (fac * cp1[2] * cp2[2]), 255*255);
 }
 
 static void blend_color_lighten(char cp[3], const char cp1[3], const char cp2[3], const int fac)
@@ -123,7 +124,7 @@
 
 static void blend_color_erase_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
 {
-	int temp = (cp1[3] - fac * cp2[3] / 255);
+	int temp = divide_round_i(cp1[3] - fac * cp2[3], 255);
 
 	cp[0] = cp1[0];
 	cp[1] = cp1[1];
@@ -133,7 +134,7 @@
 
 static void blend_color_add_alpha(char cp[4], const char cp1[4], const char cp2[4], const int fac)
 {
-	int temp = (cp1[3] + fac * cp2[3] / 255);
+	int temp = divide_round_i(cp1[3] + fac * cp2[3], 255);
 
 	cp[0] = cp1[0];
 	cp[1] = cp1[1];
@@ -175,11 +176,11 @@
 	}
 
 	if (mode == IMB_BLEND_ERASE_ALPHA) {
-		temp = (cp1[3] - fac * cp2[3] / 255);

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list