[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [58021] branches/soc-2013-paint/source/ blender/editors/sculpt_paint/paint_image_proj.c: Use undo tile colours and masks as projection pixel original colours and

Antony Riakiotakis kalast at gmail.com
Fri Jul 5 16:26:49 CEST 2013


Revision: 58021
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=58021
Author:   psy-fi
Date:     2013-07-05 14:26:49 +0000 (Fri, 05 Jul 2013)
Log Message:
-----------
Use undo tile colours and masks as projection pixel original colours and
accumulation masks respectively. This will solve artifacts when painting
on meshes where two faces reference the same region in UV space. Of
course, painting on a multithreaded system is bound to create some
conflicts if you paint with a brush that will put different colours on
the same region (for instance a textured brush), but at least you don't
get the final colour reset to the original due to a pixel still having a
zero accumulated mask in screen space.

For more correct results, synchronization (locking) on accululated mask
writing should occur but I don't think this is too crucial and it will
hurt performace somewhat if it is added. More tests are needed to assert
that it is indeed not necessary.

Modified Paths:
--------------
    branches/soc-2013-paint/source/blender/editors/sculpt_paint/paint_image_proj.c

Modified: branches/soc-2013-paint/source/blender/editors/sculpt_paint/paint_image_proj.c
===================================================================
--- branches/soc-2013-paint/source/blender/editors/sculpt_paint/paint_image_proj.c	2013-07-05 13:10:53 UTC (rev 58020)
+++ branches/soc-2013-paint/source/blender/editors/sculpt_paint/paint_image_proj.c	2013-07-05 14:26:49 UTC (rev 58021)
@@ -298,14 +298,14 @@
 	 * Store the max mask value to avoid painting over an area with a lower opacity
 	 * with an advantage that we can avoid touching the pixel at all, if the
 	 * new mask value is lower then mask_accum */
-	unsigned short mask_accum;
+	unsigned short *mask_accum;
 
 	/* for various reasons we may want to mask out painting onto this pixel */
 	unsigned short mask;
 
 	short x_px, y_px;
 
-	PixelStore origColor;
+	PixelPointer origColor;
 	PixelStore newColor;
 	PixelPointer pixel;
 
@@ -1341,18 +1341,20 @@
 static ProjPixel *project_paint_uvpixel_init(
         const ProjPaintState *ps,
         MemArena *arena,
-        const ImBuf *ibuf,
+        const ProjPaintImage *projima,
         short x_px, short y_px,
         const float mask,
         const int face_index,
-        const int image_index,
         const float pixelScreenCo[4],
         const float world_spaceCo[3],
         const int side,
-        const float w[3])
+        const float w[3],
+        const int tile_offset,
+        const int tile_index)
 {
 	ProjPixel *projPixel;
 
+	ImBuf *ibuf = projima->ibuf;
 	/* wrap pixel location */
 	x_px = x_px % ibuf->x;
 	if (x_px < 0) x_px += ibuf->x;
@@ -1365,15 +1367,12 @@
 
 	if (ibuf->rect_float) {
 		projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
-		projPixel->origColor.f[0] = projPixel->pixel.f_pt[0];
-		projPixel->origColor.f[1] = projPixel->pixel.f_pt[1];
-		projPixel->origColor.f[2] = projPixel->pixel.f_pt[2];
-		projPixel->origColor.f[3] = projPixel->pixel.f_pt[3];
+		projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
 		zero_v4(projPixel->newColor.f);
 	}
 	else {
 		projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
-		projPixel->origColor.uint = *projPixel->pixel.uint_pt;
+		projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
 		projPixel->newColor.uint = 0;
 	}
 
@@ -1388,7 +1387,10 @@
 	projPixel->y_px = y_px;
 
 	projPixel->mask = (unsigned short)(mask * 65535);
-	projPixel->mask_accum = 0;
+	if (ps->do_masking)
+		projPixel->mask_accum = (unsigned short *)projima->maskRect[tile_index] + tile_offset;
+	else
+		projPixel->mask_accum = NULL;
 
 	/* which bounding box cell are we in?, needed for undo */
 	projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
@@ -1463,7 +1465,8 @@
 	if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
 	else                  projPixel->pixel.ch_pt[0] = 0;
 #endif
-	projPixel->image_index = image_index;
+	/* pointer arithmetics */
+	projPixel->image_index = projima - ps->projImages;
 
 	return projPixel;
 }
@@ -2167,9 +2170,46 @@
 	return 1;
 }
 
+static void project_paint_undo_tiles_init(rcti *bounds_px, ProjPaintImage *pjIma, ImBuf **tmpibuf, int tile_width, bool threaded, bool do_masking)
+{
+	int tilex, tiley, tilew, tileh, tx, ty;
+	unsigned short *maskrect;
+
+	/* find the tiles covered by this face and make sure they are initialized */
+	imapaint_region_tiles(pjIma->ibuf, bounds_px->xmin, bounds_px->ymin,
+	                      bounds_px->xmax - bounds_px->xmin, bounds_px->ymax - bounds_px->ymin,
+	                      &tilex, &tiley, &tilew, &tileh);
+
+	if (threaded)
+		BLI_lock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
+
+	for (ty = tiley; ty <= tileh; ty++) {
+		for (tx = tilex; tx <= tilew; tx++) {
+			int tileindex = tx + tile_width * ty;
+
+			if (!pjIma->undoRect[tileindex]) {
+				if (do_masking) {
+					pjIma->undoRect[tileindex] = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tmpibuf, tx, ty, &maskrect);
+					pjIma->maskRect[tileindex] = maskrect;
+				}
+				else
+					pjIma->undoRect[tileindex] = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tmpibuf, tx, ty, NULL);
+
+				pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
+			}
+			else {
+
+			}
+		}
+	}
+
+	if (threaded)
+		BLI_unlock_thread(LOCK_CUSTOM1);
+}
+
 /* One of the most important function for projection painting, since it selects the pixels to be added into each bucket.
  * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
-static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, ImBuf *ibuf, const short clamp_u, const short clamp_v)
+static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
 {
 	/* Projection vars, to get the 3D locations into screen space  */
 	MemArena *arena = ps->arena_mt[thread_index];
@@ -2197,6 +2237,7 @@
 	float pixelScreenCo[4];
 	bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
 
+	bool threaded = (ps->thread_tot > 1);
 	rcti bounds_px; /* ispace bounds */
 	/* vars for getting uvspace bounds */
 
@@ -2289,10 +2330,6 @@
 #endif
 
 		if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
-			int tilex, tiley, tilew, tileh, tx, ty;
-			ImBuf *tmpibuf = NULL;
-			unsigned short *maskrect;
-
 			if (clamp_u) {
 				CLAMP(bounds_px.xmin, 0, ibuf->x);
 				CLAMP(bounds_px.xmax, 0, ibuf->x);
@@ -2303,35 +2340,9 @@
 				CLAMP(bounds_px.ymax, 0, ibuf->y);
 			}
 
-			/* find the tiles covered by this face and make sure they are initialized */
-			imapaint_region_tiles(ibuf, bounds_px.xmin, bounds_px.ymin,
-			                      bounds_px.xmax - bounds_px.xmin, bounds_px.ymax - bounds_px.ymin,
-			                      &tilex, &tiley, &tilew, &tileh);
+			project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
+			                              tile_width, threaded, ps->do_masking);
 
-			if (ps->thread_tot > 1)
-				BLI_lock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
-
-			for (ty = tiley; ty <= tileh; ty++) {
-				for (tx = tilex; tx <= tilew; tx++) {
-					int tileindex = tx + tile_width * ty;
-
-					if (!ps->projImages[image_index].undoRect[tileindex]) {
-						ps->projImages[image_index].undoRect[tileindex] = image_undo_push_tile(ps->projImages[image_index].ima, ibuf, &tmpibuf, tx, ty, &maskrect);
-						ps->projImages[image_index].maskRect[tileindex] = maskrect;
-						ibuf->userflags |= IB_BITMAPDIRTY;
-					}
-					else {
-
-					}
-				}
-			}
-
-			if (tmpibuf)
-				IMB_freeImBuf(tmpibuf);
-
-			if (ps->thread_tot > 1)
-				BLI_unlock_thread(LOCK_CUSTOM1);
-
 			/* clip face and */
 
 			has_isect = 0;
@@ -2373,10 +2384,21 @@
 							mask = project_paint_uvpixel_mask(ps, face_index, side, w);
 
 							if (mask > 0.0f) {
+								/* calculate the undo tile offset of the pixel, used to store the original
+								 * pixel colour and acculmuated mask if any */
+								int x_tile =  x >> IMAPAINT_TILE_BITS;
+								int y_tile =  y >> IMAPAINT_TILE_BITS;
+
+								int x_round = x_tile * IMAPAINT_TILE_SIZE;
+								int y_round = y_tile * IMAPAINT_TILE_SIZE;
+
+								int tile_offset = (x - x_round) + (y - y_round) * IMAPAINT_TILE_SIZE;
+								int tile_index = x_tile + y_tile * tile_width;
+
 								BLI_linklist_prepend_arena(
 								        bucketPixelNodes,
-								        project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
-								                                   image_index, pixelScreenCo, wco, side, w),
+								        project_paint_uvpixel_init(ps, arena, ps->projImages + image_index, x, y, mask, face_index,
+								                                   pixelScreenCo, wco, side, w, tile_offset, tile_index),
 								        arena
 								        );
 							}
@@ -2408,7 +2430,7 @@
 	if (ps->seam_bleed_px > 0.0f) {
 		int face_seam_flag;
 
-		if (ps->thread_tot > 1)
+		if (threaded)
 			BLI_lock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
 
 		face_seam_flag = ps->faceSeamFlags[face_index];
@@ -2426,7 +2448,7 @@
 
 		if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
 
-			if (ps->thread_tot > 1)
+			if (threaded)
 				BLI_unlock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
 
 		}
@@ -2451,7 +2473,7 @@
 				uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4);
 
 			/* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
-			if (ps->thread_tot > 1)
+			if (threaded)
 				BLI_unlock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
 
 			vCoSS[0] = ps->screenCoords[mf->v1];
@@ -2506,6 +2528,9 @@
 						if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) {
 							/* bounds between the seam rect and the uvspace bucket pixels */
 
+							project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
+			                                              tile_width, threaded, ps->do_masking);
+
 							has_isect = 0;
 							for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
 								// uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
@@ -2593,9 +2618,21 @@
 											mask = project_paint_uvpixel_mask(ps, face_index, side, w);
 
 											if (mask > 0.0f) {
+												/* calculate the undo tile offset of the pixel, used to store the original
+												 * pixel colour and acculmuated mask if any */
+												int x_tile =  x >> IMAPAINT_TILE_BITS;
+												int y_tile =  y >> IMAPAINT_TILE_BITS;
+
+												int x_round = x_tile * IMAPAINT_TILE_SIZE;
+												int y_round = y_tile * IMAPAINT_TILE_SIZE;
+
+												int tile_offset = (x - x_round) + (y - y_round) * IMAPAINT_TILE_SIZE;
+												int tile_index = x_tile + y_tile * tile_width;
+
 												BLI_linklist_prepend_arena(
 												        bucketPixelNodes,

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list