Seam Cutting in Faceselect Mode:
[blender.git] / source / blender / src / drawview.c
index 28001e2918d373fcdd1fe44df1452d803bd3f43a..26704d4d8765ea28c7840a2cafbb45fffde2831c 100644 (file)
@@ -49,6 +49,7 @@
 #include "BMF_Api.h"
 
 #include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
 
 #include "DNA_action_types.h"
 #include "DNA_armature_types.h"
@@ -1054,7 +1055,143 @@ void backdrawview3d(int test)
 
 }
 
+void check_backbuf(void)
+{
+       if(G.vd->flag & V3D_NEEDBACKBUFDRAW)
+               backdrawview3d(0);
+}
+
+/* samples a single pixel (copied from vpaint) */
+unsigned int sample_backbuf(int x, int y)
+{
+       unsigned int col;
+       
+       if(x>=curarea->winx || y>=curarea->winy) return 0;
+       x+= curarea->winrct.xmin;
+       y+= curarea->winrct.ymin;
+       
+       check_backbuf(); // actually not needed for apple
+
+#ifdef __APPLE__
+       glReadBuffer(GL_AUX0);
+#endif
+       glReadPixels(x,  y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,  &col);
+       glReadBuffer(GL_BACK);  
+       
+       if(G.order==B_ENDIAN) SWITCH_INT(col);
+       
+       return framebuffer_to_index(col);
+}
+
+/* reads full rect, converts indices */
+ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax)
+{
+       unsigned int *dr, *rd;
+       struct ImBuf *ibuf, *ibuf1;
+       int a;
+       short xminc, yminc, xmaxc, ymaxc, xs, ys;
+       
+       /* clip */
+       if(xmin<0) xminc= 0; else xminc= xmin;
+       if(xmax>=curarea->winx) xmaxc= curarea->winx-1; else xmaxc= xmax;
+       if(xminc > xmaxc) return NULL;
+
+       if(ymin<0) yminc= 0; else yminc= ymin;
+       if(ymax>=curarea->winy) ymaxc= curarea->winy-1; else ymaxc= ymax;
+       if(yminc > ymaxc) return NULL;
+       
+       ibuf= IMB_allocImBuf((xmaxc-xminc+1),(ymaxc-yminc+1),32,IB_rect,0);
+
+       check_backbuf(); // actually not needed for apple
+       
+#ifdef __APPLE__
+       glReadBuffer(GL_AUX0);
+#endif
+       glReadPixels(curarea->winrct.xmin+xminc, curarea->winrct.ymin+yminc, (xmaxc-xminc+1), (ymaxc-yminc+1), GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+       glReadBuffer(GL_BACK);  
+
+       if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+       a= (xmaxc-xminc+1)*(ymaxc-yminc+1);
+       dr= ibuf->rect;
+       while(a--) {
+               if(*dr) *dr= framebuffer_to_index(*dr);
+               dr++;
+       }
+       
+       /* put clipped result back, if needed */
+       if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax) return ibuf;
+       ibuf1= IMB_allocImBuf( (xmax-xmin+1),(ymax-ymin+1),32,IB_rect,0);
+       rd= ibuf->rect;
+       dr= ibuf1->rect;
                
+       for(ys= ymin; ys<=ymax; ys++) {
+               for(xs= xmin; xs<=xmax; xs++, dr++) {
+                       if( xs>=xminc && xs<=xmaxc && ys>=yminc && ys<=ymaxc) {
+                               *dr= *rd;
+                               rd++;
+                       }
+               }
+       }
+       IMB_freeImBuf(ibuf);
+       return ibuf1;
+}
+
+/* smart function to sample a rect spiralling outside, nice for backbuf selection */
+unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, short *dist)
+{
+       struct ImBuf *buf;
+       unsigned int *bufmin, *bufmax, *tbuf;
+       int minx, miny;
+       int a, b, rc, nr, amount, dirvec[4][2];
+       short distance=0;
+       unsigned int index = 0;
+       
+       amount= (size-1)/2;
+
+       minx = mval[0]-(amount+1);
+       miny = mval[1]-(amount+1);
+       buf = read_backbuf(minx, miny, minx+size-1, miny+size-1);
+       if (!buf) return 0;
+
+       rc= 0;
+       
+       dirvec[0][0]= 1; dirvec[0][1]= 0;
+       dirvec[1][0]= 0; dirvec[1][1]= -size;
+       dirvec[2][0]= -1; dirvec[2][1]= 0;
+       dirvec[3][0]= 0; dirvec[3][1]= size;
+       
+       bufmin = buf->rect;
+       tbuf = buf->rect;
+       bufmax = buf->rect + size*size;
+       tbuf+= amount*size+ amount;
+       
+       for(nr=1; nr<=size; nr++) {
+               
+               for(a=0; a<2; a++) {
+                       for(b=0; b<nr; b++, distance++) {
+                               if (*tbuf && *tbuf>=min && *tbuf<max) {
+                                       *dist= (short) sqrt( (float)distance ); // XXX, this distance is wrong - zr
+                                       index = *tbuf - min+1; // messy yah, but indices start at 1
+                                       goto exit;
+                               }
+                               
+                               tbuf+= (dirvec[rc][0]+dirvec[rc][1]);
+                               
+                               if(tbuf<bufmin || tbuf>=bufmax) {
+                                       goto exit;
+                               }
+                       }
+                       rc++;
+                       rc &= 3;
+               }
+       }
+
+exit:
+       IMB_freeImBuf(buf);
+       return index;
+}
+
 void drawname(Object *ob)
 {
        cpack(0x404040);