Revision: 17698
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17698
Author:   campbellbarton
Date:     2008-12-03 18:36:50 +0100 (Wed, 03 Dec 2008)

Log Message:
-----------
* added uvco_to_wrapped_pxco to get the pixel x/y from a UV that could be 
outside 0-1 range.
* use 80deg rather then 90 for the "Normal" painting option, since painting 
faces that are very close to 90d to the view gives some artifacts.
* Brecht modified the Barycentric weights function to use a signed area. so 
BarycentricWeightsSimplePersp2f and BarycentricWeightsSimple2f these funcs are 
not needed anymore.

2 bugs with seams fixed
* triangle faces seams were not being filled correctly - causing visible seams
* the pretend 3D location for seam pixels was too close to the face edge - 
causing some pixels to be occluded by the adjacent face.

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-12-03 
17:36:30 UTC (rev 17697)
+++ branches/projection-paint/source/blender/src/imagepaint.c   2008-12-03 
17:36:50 UTC (rev 17698)
@@ -174,6 +174,11 @@
 #define PROJ_FACE_NOSEAM3      1<<6
 #define PROJ_FACE_NOSEAM4      1<<7
 
+/* a slightly scaled down face is used to get fake 3D location for edge pixels 
in the seams
+ * as this number approaches  1.0f the likelihood increases of float precision 
errors where
+ * it is occluded by an adjacent face */
+#define PROJ_FACE_SCALE_SEAM   0.99f
+
 #define PROJ_BUCKET_NULL               0
 #define PROJ_BUCKET_INIT               1<<0
 // #define PROJ_BUCKET_CLONE_INIT      1<<1
@@ -181,6 +186,9 @@
 /* vert flags */
 #define PROJ_VERT_CULL 1
 
+/* M_PI_2 is 90d, we want 80 though */
+#define PI_80_DEG ((M_PI_2 / 9) * 8)
+
 /* This is mainly a convenience struct used so we can keep an array of images 
we use
  * Thir imbufs, etc, in 1 array, When using threads this array is copied for 
each thread
  * because 'partRedrawRect' and 'touch' values would not be thread safe */
@@ -504,49 +512,32 @@
        }
 }
 
-/* The point must be inside the triangle */
-static void BarycentricWeightsSimple2f(float v1[2], float v2[2], float v3[2], 
float pt[2], float w[3])
+#define SIDE_OF_LINE(pa, pb, pp)       
((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
+
+static float AreaSignedF2Dfl(float *v1, float *v2, float *v3)
 {
-       float wtot, wtot_inv;
-       w[0] = AreaF2Dfl(v2, v3, pt);
-       w[1] = AreaF2Dfl(v3, v1, pt);
-       w[2] = AreaF2Dfl(v1, v2, pt);
-       wtot = w[0]+w[1]+w[2];
-       if (wtot > 0.0f) { /* just incase */
-               wtot_inv = 1.0f / wtot; 
-               w[0]*=wtot_inv;
-               w[1]*=wtot_inv;
-               w[2]*=wtot_inv;
-       }
-       else {
-               w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area 
face */
-       }
+   return (float)(0.5f*((v1[0]-v2[0])*(v2[1]-v3[1]) +
+(v1[1]-v2[1])*(v3[0]-v2[0])));
 }
 
-/* also works for points outside the triangle */
-#define SIDE_OF_LINE(pa, pb, pp)       
((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
 static void BarycentricWeights2f(float v1[2], float v2[2], float v3[2], float 
pt[2], float w[3])
 {
-       float wtot_inv, wtot = AreaF2Dfl(v1, v2, v3);
-       if (wtot > 0.0f) {
-               wtot_inv = 1.0f / wtot;
-               w[0] = AreaF2Dfl(v2, v3, pt);
-               w[1] = AreaF2Dfl(v3, v1, pt);
-               w[2] = AreaF2Dfl(v1, v2, pt);
-               
-               /* negate weights when 'pt' is on the outer side of the the 
triangles edge */
-               if ((SIDE_OF_LINE(v2,v3, pt)>0.0f) != (SIDE_OF_LINE(v2,v3, 
v1)>0.0f))   w[0]*= -wtot_inv;
-               else                                                            
                                                                w[0]*=  
wtot_inv;
+   float wtot_inv, wtot, wsign[3];
 
-               if ((SIDE_OF_LINE(v3,v1, pt)>0.0f) != (SIDE_OF_LINE(v3,v1, 
v2)>0.0f))   w[1]*= -wtot_inv;
-               else                                                            
                                                                w[1]*=  
wtot_inv;
+   wsign[0] = AreaSignedF2Dfl(v2, v3, pt);
+   wsign[1] = AreaSignedF2Dfl(v3, v1, pt);
+   wsign[2] = AreaSignedF2Dfl(v1, v2, pt);
+   wtot = wsign[0]+wsign[1]+wsign[2];
 
-               if ((SIDE_OF_LINE(v1,v2, pt)>0.0f) != (SIDE_OF_LINE(v1,v2, 
v3)>0.0f))   w[2]*= -wtot_inv;
-               else                                                            
                                                                w[2]*=  
wtot_inv;
-       }
-       else {
-               w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area 
face */
-       }
+   if (fabs(wtot) > 0.0f) {
+       wtot_inv = 1.0f/wtot;
+
+       w[0] = wsign[0]*wtot_inv;
+       w[1] = wsign[1]*wtot_inv;
+       w[2] = wsign[2]*wtot_inv;
+   }
+   else /* dummy values for zero area face */
+       w[0] = w[1] = w[2] = 1.0f/3.0f;
 }
 
 /* still use 2D X,Y space but this works for verts transformed by a 
perspective matrix, using their 4th component as a weight */
@@ -572,27 +563,6 @@
        }
 }
 
-static void BarycentricWeightsSimplePersp2f(float v1[4], float v2[4], float 
v3[4], float pt[2], float w[3])
-{
-       float persp_tot_inv, persp_tot;
-       BarycentricWeightsSimple2f(v1, v2, v3, pt, w);
-       
-       w[0] /= v1[3];
-       w[1] /= v2[3];
-       w[2] /= v3[3];
-       
-       persp_tot = w[0]+w[1]+w[2];
-       if (persp_tot > 0.0f) {
-               persp_tot_inv = 1.0f / persp_tot;
-               w[0] *= persp_tot_inv;
-               w[1] *= persp_tot_inv;
-               w[2] *= persp_tot_inv;
-       }
-       else {
-               w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area 
face */
-       }
-}
-
 static void VecWeightf(float p[3], const float v1[3], const float v2[3], const 
float v3[3], const float w[3])
 {
        p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2];
@@ -608,7 +578,7 @@
 
 static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], 
float w[3])
 {
-       BarycentricWeightsSimple2f(v1, v2, v3, pt, w);
+       BarycentricWeights2f(v1, v2, v3, pt, w);
        return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
 }
 
@@ -671,6 +641,20 @@
        return best_face_index; /* will be -1 or a valid face */
 }
 
+/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 
range */
+static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float 
*x, float *y)
+{
+       /* use */
+       *x = (float)fmod(uv[0], 1.0f);
+       *y = (float)fmod(uv[1], 1.0f);
+       
+       if (*x < 0.0f) *x += 1.0f;
+       if (*y < 0.0f) *y += 1.0f;
+       
+       *x = *x * ibuf_x - 0.5f;
+       *y = *y * ibuf_y - 0.5f;
+}
+
 /* Set the top-most face color that the screen space coord 'pt' touches (or 
return 0 if none touch) */
 static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], 
float *rgba_fp, unsigned char *rgba, const int interp)
 {
@@ -702,16 +686,8 @@
        
        if (interp) {
                float x, y;
-               /* use */
-               x = (float)fmod(uv[0], 1.0f);
-               y = (float)fmod(uv[1], 1.0f);
+               uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
                
-               if (x < 0.0f) x += 1.0f;
-               if (y < 0.0f) y += 1.0f;
-               
-               x = x * ibuf->x - 0.5f;
-               y = y * ibuf->y - 0.5f;
-               
                if (ibuf->rect_float) {
                        if (rgba_fp) {
                                bilinear_interpolation_color(ibuf, NULL, 
rgba_fp, x, y);
@@ -1255,7 +1231,7 @@
                float pixelScreenCo[4],
                float w[3])
 {
-       BarycentricWeightsSimple2f(uv1co, uv2co, uv3co, uv, w);
+       BarycentricWeights2f(uv1co, uv2co, uv3co, uv, w);
        VecWeightf(pixelScreenCo, v1co, v2co, v3co, w);
 }
 
@@ -1270,7 +1246,7 @@
 {
 
        float wtot_inv, wtot;
-       BarycentricWeightsSimple2f(uv1co, uv2co, uv3co, uv, w);
+       BarycentricWeights2f(uv1co, uv2co, uv3co, uv, w);
        
        /* re-weight from the 4th coord of each screen vert */
        w[0] *= v1co[3];
@@ -1347,16 +1323,16 @@
                        angle = NormalizedVecAngle2(viewDirPersp, no);
                }
                
-               if (angle >= M_PI_2) {
+               if (angle >= PI_80_DEG) {
                        return 0.0f;
                }
                else {
 #if 0
-                       mask = 1.0f - (angle / M_PI_2); /* map angle to 
1.0-facing us, 0.0 right angles to the view direction */
+                       mask = 1.0f - (angle / PI_80_DEG); /* map angle to 
1.0-facing us, 0.0 right angles to the view direction */
 #endif
                        
                        /* trickier method that clips the normal so its more 
useful */
-                       mask = (angle / M_PI_2); /* map angle to 1.0-facing us, 
0.0 right angles to the view direction */
+                       mask = (angle / PI_80_DEG); /* map angle to 1.0-facing 
us, 0.0 right angles to the view direction */
                        mask = (1.0f - (mask * mask * mask)) * 1.4f;
                        if (mask > 1.0f) {
                                mask = 1.0f;
@@ -1380,7 +1356,7 @@
                const ProjPaintState *ps,
                MemArena *arena,
                const ImBuf *ibuf,
-               short x, short y,
+               short x_px, short y_px,
                const float mask,
                const int face_index,
                const int image_index,
@@ -1392,10 +1368,10 @@
        short size;
        
        /* wrap pixel location */
-       x = x % ibuf->x;
-       if (x<0) x += ibuf->x;
-       y = y % ibuf->y;
-       if (y<0) y += ibuf->y;
+       x_px = x_px % ibuf->x;
+       if (x_px<0) x_px += ibuf->x;
+       y_px = y_px % ibuf->y;
+       if (y_px<0) y_px += ibuf->y;
        
        if (ps->tool==PAINT_TOOL_CLONE) {
                size = sizeof(ProjPixelClone);
@@ -1410,27 +1386,27 @@
        projPixel = (ProjPixel *)BLI_memarena_alloc(arena, size);
        
        if (ibuf->rect_float) {
-               projPixel->pixel.f_pt = (float *)ibuf->rect_float + ((x + y * 
ibuf->x) * 4);
+               projPixel->pixel.f_pt = (float *)ibuf->rect_float + ((x_px + 
y_px * ibuf->x) * 4);
                projPixel->origColor.f[0] = projPixel->newColor.f[0] = 
projPixel->pixel.f_pt[0];  
                projPixel->origColor.f[1] = projPixel->newColor.f[1] = 
projPixel->pixel.f_pt[1];  
                projPixel->origColor.f[2] = projPixel->newColor.f[2] = 
projPixel->pixel.f_pt[2];  
                projPixel->origColor.f[3] = projPixel->newColor.f[3] = 
projPixel->pixel.f_pt[3];  
        }
        else {
-               projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x + y 
* ibuf->x) * 4));
+               projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px 
+ y_px * ibuf->x) * 4));
                projPixel->origColor.uint = projPixel->newColor.uint = 
*projPixel->pixel.uint_pt;
        }
        
        /* screenspace unclamped, we could keep its z and w values but dont 
need them at the moment */
        VECCOPY2D(projPixel->projCoSS, pixelScreenCo);
        
-       projPixel->x_px = x;
-       projPixel->y_px = y;
+       projPixel->x_px = x_px;
+       projPixel->y_px = y_px;
        
        projPixel->mask = mask;
        
        /* which bounding box cell are we in?, needed for undo */
-       projPixel->bb_cell_index = ((int)((((float)x)/((float)ibuf->x)) * 
PROJ_BOUNDBOX_DIV)) + ((int)((((float)y)/((float)ibuf->y)) * 
PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV ;
+       projPixel->bb_cell_index = ((int)(((float)x_px/(float)ibuf->x) * 
PROJ_BOUNDBOX_DIV)) + ((int)(((float)y_px/(float)ibuf->y) * PROJ_BOUNDBOX_DIV)) 
* PROJ_BOUNDBOX_DIV ;
        
        
        /* done with view3d_project_float inline */
@@ -1458,8 +1434,7 @@
                                Vec2Weightf(uv_other, uvCo1, uvCo2, uvCo3, w);
                                
                                /* use */
-                               x = (float)fmod(uv_other[0], 1.0f);
-                               y = (float)fmod(uv_other[1], 1.0f);
+                               uvco_to_wrapped_pxco(uv_other, ibuf->x, 
ibuf->y, &x, &y);
                                
                                if (x < 0.0f) x += 1.0f;
                                if (y < 0.0f) y += 1.0f;
@@ -1618,7 +1593,7 @@
 
 
 /* scale the quad & tri about its center
- * scaling by 0.99999 is used for getting fake UV pixel coords that are on the
+ * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel 
coords that are on the
  * edge of the face but slightly inside it occlusion tests dont return hits on 
adjacent faces */
 static void scale_quad(float insetCos[4][3], float *origCos[4], const float 
inset)
 {
@@ -1748,22 +1723,22 @@
        /* get the UV space bounding box */
        uv[0] = bucket_bounds->xmax;
        uv[1] = bucket_bounds->ymin;
-       BarycentricWeightsSimple2f(v1coSS, v2coSS, v3coSS, uv, w);      
+       BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);    
        Vec2Weightf(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w);
 
        //uv[0] = bucket_bounds->xmax; // set above
        uv[1] = bucket_bounds->ymax;
-       BarycentricWeightsSimple2f(v1coSS, v2coSS, v3coSS, uv, w);
+       BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
        Vec2Weightf(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w);
 
        uv[0] = bucket_bounds->xmin;
        //uv[1] = bucket_bounds->ymax; // set above

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to