[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [60883] branches/soc-2013-paint/source/ blender/editors/sculpt_paint/paint_image_proj.c: Simplify undo pushing for projection painting.

Antony Riakiotakis kalast at gmail.com
Mon Oct 21 18:32:17 CEST 2013


Revision: 60883
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=60883
Author:   psy-fi
Date:     2013-10-21 16:32:16 +0000 (Mon, 21 Oct 2013)
Log Message:
-----------
Simplify undo pushing for projection painting.

* Do not compare image pixels at end of stroke, it causes a great
stutter at the end of painting on large images (4096x4096 in my test
case). In any case tiles have been pushed already for such images.

* Only add tile if pixel passes the mask test. Previous approach could
add tiles even for clipped pixels.

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-10-21 15:44:09 UTC (rev 60882)
+++ branches/soc-2013-paint/source/blender/editors/sculpt_paint/paint_image_proj.c	2013-10-21 16:32:16 UTC (rev 60883)
@@ -330,6 +330,16 @@
 	PixelStore clonepx;
 } ProjPixelClone;
 
+/* undo tile pushing */
+typedef struct {
+	bool threaded;
+	bool masked;
+	unsigned short tile_width;
+	ImBuf **tmpibuf;
+	ProjPaintImage *pjima;
+} TileInfo;
+
+
 /* Finish projection painting structs */
 
 static Image *project_paint_face_image(const ProjPaintState *ps, int face_index)
@@ -1380,26 +1390,53 @@
 	}
 }
 
+static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
+{
+	unsigned short *maskrect;
+	ProjPaintImage *pjIma = tinf->pjima;
 
+	int tileindex = tx + ty * tinf->tile_width;
+
+	if (tinf->threaded)
+		BLI_lock_thread(LOCK_CUSTOM1);  /* Other threads could be modifying these vars */
+
+	if (UNLIKELY(!pjIma->undoRect[tileindex])) {
+		if (tinf->masked) {
+			pjIma->undoRect[tileindex] = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &maskrect);
+			pjIma->maskRect[tileindex] = maskrect;
+		}
+		else
+			pjIma->undoRect[tileindex] = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL);
+
+		pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
+	}
+
+	if (tinf->threaded)
+		BLI_unlock_thread(LOCK_CUSTOM1);
+
+	return tileindex;
+}
+
 /* run this function when we know a bucket's, face's pixel can be initialized,
  * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
 static ProjPixel *project_paint_uvpixel_init(
         const ProjPaintState *ps,
         MemArena *arena,
-        const ProjPaintImage *projima,
+        const TileInfo *tinf,
         int x_px, int y_px,
         const float mask,
         const int face_index,
         const float pixelScreenCo[4],
         const float world_spaceCo[3],
         const int side,
-        const float w[3], unsigned int tile_width)
+        const float w[3])
 {
 	ProjPixel *projPixel;
 	int x_tile, y_tile;
 	int x_round, y_round;
 	int tile_offset, tile_index;
 
+	ProjPaintImage *projima = tinf->pjima;
 	ImBuf *ibuf = projima->ibuf;
 	/* wrap pixel location */
 
@@ -1415,11 +1452,10 @@
 	y_round = y_tile * IMAPAINT_TILE_SIZE;
 
 	tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
-	tile_index = x_tile + y_tile * tile_width;
+	tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
 
 	BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
 	BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
-	BLI_assert(projima->undoRect[tile_index] != NULL);
 
 	BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
 	projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
@@ -2232,112 +2268,6 @@
 	return 1;
 }
 
-static void project_paint_undo_subtiles(rcti *bounds_px, ProjPaintImage *pjIma, ImBuf **tmpibuf, unsigned short 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);
-
-}
-
-/* check if boundary rectangle of face in uv space exceeds the image boundaries and if it does, create subrectangles to properly initialize the tiles */
-static void project_paint_undo_tiles_init(rcti *bounds_px, ProjPaintImage *pjIma, ImBuf **tmpibuf, unsigned short tile_width, bool threaded, bool do_masking)
-{
-	rcti rect;
-	ImBuf *ibuf = pjIma->ibuf;
-	/* first determine if bounds rectangle exceeds the ibuf bounds, and if it does, create
-	 * extra rectangles to initialize the tiles from. The rectangles get clipped so it shouldn't
-	 * generate any unneeded tiles */
-	if (bounds_px->xmin < 0) {
-		rect.xmin = ibuf->x + bounds_px->xmin;
-		rect.xmax = ibuf->x;
-		rect.ymin = bounds_px->ymin;
-		rect.ymax = bounds_px->ymax;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->xmax >= ibuf->x) {
-		rect.xmin = 0;
-		rect.xmax = bounds_px->xmax - ibuf->x + 1;
-		rect.ymin = bounds_px->ymin;
-		rect.ymax = bounds_px->ymax;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->ymin < 0) {
-		rect.xmax = bounds_px->xmax;
-		rect.xmin = bounds_px->xmin;
-		rect.ymin = ibuf->y + bounds_px->ymin;
-		rect.ymax = ibuf->y;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->ymax >= ibuf->y) {
-		rect.xmax = bounds_px->xmax;
-		rect.xmin = bounds_px->xmin;
-		rect.ymin = 0;
-		rect.ymax = bounds_px->ymax - ibuf->y + 1;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	/* finally check the diagonals */
-	if (bounds_px->xmin < 0 && bounds_px->ymin < 0) {
-		rect.xmin = ibuf->x + bounds_px->xmin;
-		rect.xmax = ibuf->x;
-		rect.ymin = ibuf->y + bounds_px->ymin;
-		rect.ymax = ibuf->y;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->xmax >= ibuf->x && bounds_px->ymax >= ibuf->y) {
-		rect.xmin = 0;
-		rect.xmax = bounds_px->xmax - ibuf->x + 1;
-		rect.ymin = 0;
-		rect.ymax = bounds_px->ymax - ibuf->y + 1;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->xmin < 0 && bounds_px->ymax >= ibuf->y) {
-		rect.xmin = ibuf->x + bounds_px->xmin;
-		rect.xmax = ibuf->x;
-		rect.ymin = 0;
-		rect.ymax = bounds_px->ymax - ibuf->y + 1;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	if (bounds_px->xmax >= ibuf->x && bounds_px->ymin < 0) {
-		rect.xmin = 0;
-		rect.xmax = bounds_px->xmax - ibuf->x + 1;
-		rect.ymin = ibuf->y + bounds_px->ymin;
-		rect.ymax = ibuf->y;
-		project_paint_undo_subtiles(&rect, pjIma, tmpibuf, tile_width, threaded, do_masking);
-	}
-	/* finally do the rectangle itself */
-	project_paint_undo_subtiles(bounds_px, pjIma, tmpibuf, tile_width, threaded, do_masking);
-}
-
 /* 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, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
@@ -2347,6 +2277,13 @@
 	LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
 	LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
 
+	TileInfo tinf = {
+	                 (ps->thread_tot > 1),
+	                 ps->do_masking,
+	                 IMAPAINT_TILE_NUMBER(ibuf->x),
+                     tmpibuf,
+                     ps->projImages + image_index
+	                };
 	const MFace *mf = ps->dm_mface + face_index;
 	const MTFace *tf = ps->dm_mtface + face_index;
 
@@ -2355,7 +2292,6 @@
 	int y; /* Image Y-Pixel */
 	float mask;
 	float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
-	unsigned short tile_width;
 
 	int side;
 	float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
@@ -2427,8 +2363,6 @@
 		side = 0;
 	}
 
-	tile_width =  IMAPAINT_TILE_NUMBER(ibuf->x);
-
 	do {
 		if (side == 1) {
 			i1 = 0; i2 = 2; i3 = 3;
@@ -2471,9 +2405,10 @@
 				CLAMP(bounds_px.ymax, 0, ibuf->y);
 			}
 
+			/*
 			project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
 			                              tile_width, threaded, ps->do_masking);
-
+			*/
 			/* clip face and */
 
 			has_isect = 0;
@@ -2517,8 +2452,8 @@
 							if (mask > 0.0f) {
 								BLI_linklist_prepend_arena(
 								        bucketPixelNodes,
-								        project_paint_uvpixel_init(ps, arena, ps->projImages + image_index, x, y, mask, face_index,
-								                                   pixelScreenCo, wco, side, w, tile_width),
+								        project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+								                                   pixelScreenCo, wco, side, w),
 								        arena
 								        );
 							}
@@ -2648,9 +2583,6 @@
 						if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, true)) {
 							/* 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;
@@ -2740,8 +2672,8 @@
 											if (mask > 0.0f) {
 												BLI_linklist_prepend_arena(
 												        bucketPixelNodes,
-												        project_paint_uvpixel_init(ps, arena, ps->projImages + image_index, x, y, mask, face_index,
-												        pixelScreenCo, wco, side, w, tile_width),
+												        project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+												        pixelScreenCo, wco, side, w),
 												        arena
 												        );

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list