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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to