[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17399] branches/projection-paint/source/ blender/src/imagepaint.c: * float image buffer support

Campbell Barton ideasman42 at gmail.com
Tue Nov 11 04:43:23 CET 2008


Revision: 17399
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17399
Author:   campbellbarton
Date:     2008-11-11 04:43:21 +0100 (Tue, 11 Nov 2008)

Log Message:
-----------
* float image buffer support 
* bicubic interpolation for the clone tool

Modified Paths:
--------------
    branches/projection-paint/source/blender/src/imagepaint.c

Modified: branches/projection-paint/source/blender/src/imagepaint.c
===================================================================
--- branches/projection-paint/source/blender/src/imagepaint.c	2008-11-11 03:12:31 UTC (rev 17398)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-11 03:43:21 UTC (rev 17399)
@@ -98,12 +98,13 @@
 
 /* Defines and Structs */
 
-#define IMAPAINT_CHAR_TO_FLOAT(c) (c/255.0f)
+#define IMAPAINT_CHAR_TO_FLOAT(c) ((c)/255.0f)
 
-#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { c[0]=FTOCHAR(f[0]); \
-	c[1]=FTOCHAR(f[1]); c[2]=FTOCHAR(f[2]); }
-#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); \
-	f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); }
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCHAR((f)[1]); (c)[2]=FTOCHAR((f)[2]); }
+#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCHAR((f)[1]); (c)[2]=FTOCHAR((f)[2]); (c)[3]=FTOCHAR((f)[3]); }
+
+#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { (f)[0]=IMAPAINT_CHAR_TO_FLOAT((c)[0]); (f)[1]=IMAPAINT_CHAR_TO_FLOAT((c)[1]); (f)[2]=IMAPAINT_CHAR_TO_FLOAT((c)[2]); }
+#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { (f)[0]=IMAPAINT_CHAR_TO_FLOAT((c)[0]); (f)[1]=IMAPAINT_CHAR_TO_FLOAT((c)[1]); (f)[2]=IMAPAINT_CHAR_TO_FLOAT((c)[2]); (f)[3]=IMAPAINT_CHAR_TO_FLOAT((c)[3]); }
 #define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b)
 
 #define IMAPAINT_TILE_BITS			6
@@ -187,6 +188,7 @@
 	int bucketsY;
 	
 	Image **projectImages;			/* array of images we are painting onto while, use so we can tag for updates */
+	ImBuf **projectImBufs;			/* array of imbufs we are painting onto while, use so we can get the rect and rect_float quickly */
 	
 	int projectImageTotal;			/* size of projectImages array */
 	int imaContextIndex;			/* current image, use for context switching */
@@ -221,17 +223,20 @@
 
 typedef struct ProjectPixel {
 	float projCo2D[2]; /* the floating point screen projection of this pixel */
-	char *pixel;
+	void *pixel;
 	int image_index;
 } ProjectPixel;
 
 typedef struct ProjectPixelClone {
 	struct ProjectPixel __pp;
-	/*char backbuf[4];	*//* TODO - float buffer? */
-	char clonebuf[4];
-	//void *source;		/* pointer to source pixels */
+	char clonepx[4];
 } ProjectPixelClone;
 
+typedef struct ProjectPixelCloneFloat {
+	struct ProjectPixel __pp;
+	float clonepx[4];
+} ProjectPixelCloneFloat;
+
 /* Finish projection painting structs */
 
 
@@ -391,7 +396,7 @@
 }
 
 
-static int project_paint_BucketOffset(ProjectPaintState *ps, float *projCo2D)
+static int project_paint_BucketOffset(ProjectPaintState *ps, float projCo2D[2])
 {
 	/* If we were not dealing with screenspace 2D coords we could simple do...
 	 * ps->projectBuckets[x + (y*ps->bucketsY)] */
@@ -407,7 +412,7 @@
 		(	(	(int)(( (projCo2D[1] - ps->viewMin2D[1])  / ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
 }
 
-static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float *projCo2D)
+static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float projCo2D[2])
 {
 	int bucket_index = project_paint_BucketOffset(ps, projCo2D);
 	
@@ -556,17 +561,106 @@
 	return best_face_index; /* will be -1 or a valid face */
 }
 
+/**************************************************************************
+*                            INTERPOLATIONS 
+*
+* Reference and docs:
+* http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms
+***************************************************************************/
+
+/* BICUBIC Interpolation functions */
+/*  More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation
+*/
+/* function assumes out to be zero'ed, only does RGBA */
+static float P(float k){
+	return (float)(1.0f/6.0f)*( pow( MAX2(k+2.0f,0) , 3.0f ) - 4.0f * pow( MAX2(k+1.0f,0) , 3.0f ) + 6.0f * pow( MAX2(k,0) , 3.0f ) - 4.0f * pow( MAX2(k-1.0f,0) , 3.0f));
+}
+
+static void bicubic_interpolation_px(ImBuf *in, float x, float y, float rgba_fp[4], char rgba[4])
+{
+	int i,j,n,m,x1,y1;
+	unsigned char *dataI;
+	float a,b,w,wx,wy[4], outR,outG,outB,outA,*dataF,*outF;
+	int do_rect=0, do_float=0;
+
+	if (in == NULL) return;
+	if (in->rect == NULL && in->rect_float == NULL) return;
+
+	if (in->rect_float)	do_float = 1;
+	else				do_rect = 1;
+	
+	i= (int)floor(x);
+	j= (int)floor(y);
+	a= x - i;
+	b= y - j;
+
+	outR= 0.0f;
+	outG= 0.0f;
+	outB= 0.0f;
+	outA= 0.0f;
+	
+	/* avoid calling multiple times */
+	wy[0] = P(b-(-1));
+	wy[1] = P(b-  0);
+	wy[2] = P(b-  1);
+	wy[3] = P(b-  2);
+	
+	for(n= -1; n<= 2; n++){
+		x1= i+n;
+		if (x1>0 && x1 < in->x) {
+			wx = P(n-a);
+			for(m= -1; m<= 2; m++){
+				y1= j+m;
+				if (y1>0 && y1<in->y) {
+					/* normally we could do this */
+					/* w = P(n-a) * P(b-m); */
+					/* except that would call P() 16 times per pixel therefor pow() 64 times, better precalc these */
+					w = wx * wy[m+1];
+					
+					if (do_float) {
+						dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
+						outR+= dataF[0] * w;
+						outG+= dataF[1] * w;
+						outB+= dataF[2] * w;
+						outA+= dataF[3] * w;
+					}
+					if (do_rect) {
+						dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1;
+						outR+= dataI[0] * w;
+						outG+= dataI[1] * w;
+						outB+= dataI[2] * w;
+						outA+= dataI[3] * w;
+					}
+				}
+			}
+		}
+	}
+	if (do_rect) {
+		rgba[0]= (int)outR;
+		rgba[1]= (int)outG;
+		rgba[2]= (int)outB;
+		rgba[3]= (int)outA;
+	}
+	if (do_float) {
+		rgba_fp[0]= outR;
+		rgba_fp[1]= outG;
+		rgba_fp[2]= outB;
+		rgba_fp[3]= outA;
+	}
+}
+
 /* bucket_index is optional, since in some cases we know it */
-static int screenco_pickcol(ProjectPaintState *ps, float pt[2], char rgba[4], int interp)
+/* TODO FLOAT */ /* add a function that does this for float buffers */
+static int screenco_pickcol(ProjectPaintState *ps, float pt[2], float *rgba_fp, char *rgba, int interp)
 {
 	float w[3], uv[2];
 	int side;
 	int face_index;
 	MTFace *tf;
 	ImBuf *ibuf;
-	int x,y;
-	char *pixel;
+	int xi,yi;
 	
+	
 	face_index = screenco_pickface(ps,pt,w, &side);
 	
 	if (face_index == -1)
@@ -584,17 +678,51 @@
 	
 	ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow */
 	
-	x = uv[0]*ibuf->x;
-	y = uv[1]*ibuf->y;
+
 	
-	if (x<0 || x>=ibuf->x  ||  y<0 || y>=ibuf->y) return 0;
-	
-	pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * 4);
-	
-	rgba[0] = pixel[0];
-	rgba[1] = pixel[1];
-	rgba[2] = pixel[2];
-	rgba[3] = pixel[3];
+	if (interp) {
+		float x,y;
+		x = uv[0]*ibuf->x;
+		y = uv[1]*ibuf->y;
+		if (ibuf->rect_float) {
+			if (rgba_fp) {
+				bicubic_interpolation_px(ibuf, x, y, rgba_fp, NULL);
+			} else {
+				float rgba_tmp_fp[4];
+				bicubic_interpolation_px(ibuf, x, y, rgba_tmp_fp, NULL);
+				IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp);
+			}
+		} else {
+			if (rgba) {
+				bicubic_interpolation_px(ibuf, x, y, NULL, rgba);
+			} else {
+				char rgba_tmp[4];
+				bicubic_interpolation_px(ibuf, x, y, NULL, rgba_tmp);
+				IMAPAINT_CHAR_RGBA_TO_FLOAT( rgba_fp,  rgba_tmp);
+			}
+		}
+	} else {
+		xi = uv[0]*ibuf->x;
+		yi = uv[1]*ibuf->y;
+		
+		if (xi<0 || xi>=ibuf->x  ||  yi<0 || yi>=ibuf->y) return 0;
+		
+		if (rgba) {
+			if (ibuf->rect_float) {
+				IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, ((( float * ) ibuf->rect_float) + (( xi + yi * ibuf->x ) * 4)));
+			} else {
+				*((unsigned int *)rgba) = *(unsigned int *) ((( char * ) ibuf->rect) + (( xi + yi * ibuf->x ) * 4));
+			}
+		}
+		
+		if (rgba_fp) {
+			if (ibuf->rect_float) {
+				QUATCOPY(rgba_fp, ((( float * ) ibuf->rect_float) + (( xi + yi * ibuf->x ) * 4)));
+			} else {
+				IMAPAINT_CHAR_RGBA_TO_FLOAT( rgba_fp,  ((( char * ) ibuf->rect) + (( xi + yi * ibuf->x ) * 4)));
+			}
+		}
+	}
 	return 1;
 }
 
@@ -1151,6 +1279,7 @@
 static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, float pixelScreenCo[4])
 {
 	ProjectPixel *projPixel;
+	short size;
 	
 	// printf("adding px (%d %d), (%f %f)\n", x,y,uv[0],uv[1]);
 	
@@ -1162,39 +1291,53 @@
 	/* screenco_pickface is less complex, use for testing */
 	//if (screenco_pickface(ps, pixelScreenCo, w, &side) == face_index) {
 	if (ps->projectIsOcclude==0 || !project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
+		
+		if (ps->tool==PAINT_TOOL_CLONE) {
+			if (ibuf->rect_float) {
+				size = sizeof(ProjectPixelCloneFloat);
+			} else {
+				size = sizeof(ProjectPixelClone);
+			}
+		} else if (ps->tool==PAINT_TOOL_SMEAR) {
+			size = sizeof(ProjectPixelClone);
+		}
+		
+		projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, size);
+		
+		if (ibuf->rect_float) {
+			projPixel->pixel = (void *) ((( float * ) ibuf->rect_float) + (( x + y * ibuf->x ) * pixel_size));
+		} else {
+			projPixel->pixel = (void *) ((( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size));
+		}
+		
+		VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+		
 		/* done with view3d_project_float inline */
 		if (ps->tool==PAINT_TOOL_CLONE) {
 			float co[2];
 			
-			projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, sizeof(ProjectPixelClone));
-			projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
-			VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
-			
-			/* copy pixel color to backbuf - not used yet */
-			/* memcpy( &(((ProjectPixelClone *)projPixel)->backbuf), projPixel->pixel, pixel_size); */
-			//((ProjectPixelClone *)projPixel)->source = NULL; /* must be set later */
-			
-			
 			/* Initialize clone pixels - note that this is a bit of a waste since some of these are being indirectly initialized :/ */
 			/* TODO - possibly only run this for directly ativated buckets when cloning */
 			Vec2Subf(co, projPixel->projCo2D, ps->cloneOfs);
 			
 			/* no need to initialize the bucket, we're only checking buckets faces and for this
 			 * the faces are alredy initialized in project_paint_delayed_face_init(...) */
-			if (!screenco_pickcol(ps, co, ((ProjectPixelClone *)projPixel)->clonebuf, 1)) {
-				((ProjectPixelClone *)projPixel)->clonebuf[3] = 0; /* zero alpha - ignore */
+			if (ibuf->rect_float) {
+				if (!screenco_pickcol(ps, co, ((ProjectPixelCloneFloat *)projPixel)->clonepx, NULL, 1)) {
+					((ProjectPixelCloneFloat *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
+				}
+			} else {
+				if (!screenco_pickcol(ps, co, NULL, ((ProjectPixelClone *)projPixel)->clonepx, 1)) {
+					((ProjectPixelClone *)projPixel)->clonepx[3] = 0; /* zero alpha - ignore */
+				}
 			}

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list