Boundbox select object mode optimisation.
authorMartin Poirier <theeth@yahoo.com>
Mon, 11 Jul 2005 11:09:26 +0000 (11:09 +0000)
committerMartin Poirier <theeth@yahoo.com>
Mon, 11 Jul 2005 11:09:26 +0000 (11:09 +0000)
Changed selectprojektie (and renamed to view3d_opengl_select as suggested by Ton) to accept a buffer size, so boundbox can adapt it's buffer size to the number of object in scene.
Also, the loop is done more smartly, since glSelect fills the buffer in the same order as the drawing order, so we save lops of looping on unselected object (which used to go through all the buffer before finding that they weren't selected).

This scheme could probably be applied to all the other loops using glSelect. (good project for newbie coders)

source/blender/include/BSE_view.h
source/blender/src/editarmature.c
source/blender/src/editmball.c
source/blender/src/editview.c
source/blender/src/view.c

index 67aa7bfd6ad094e85decde658d2ea1b583604552..5a70ebb5718b053458fb2068b4b68fc816a5d6d6 100644 (file)
@@ -70,7 +70,7 @@ void centreview(void);
 void restore_localviewdata(struct View3D *vd);
 void endlocalview(struct ScrArea *sa);
 void view3d_home(int centre);
-short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2);
+short view3d_opengl_select(unsigned int *buffer, unsigned int buffsize, short x1, short y1, short x2, short y2);
 void view3d_align_axis_to_vector(struct View3D *v3d, int axisidx, float vec[3]);
 
 #endif
index 528dbefe2fbee5b131da72de8931186c8a4582b2..4663b799b4245aa0e3379d50aa769d6dfba2585a 100644 (file)
@@ -494,7 +494,7 @@ static void * get_nearest_bone (int findunsel)
        persp(PERSP_VIEW);
        
        glInitNames();
-       hits= selectprojektie(buffer, 0, 0, 0, 0);
+       hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
        
        /* See if there are any selected bones in this group */
        if (hits){
@@ -763,7 +763,7 @@ static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask)
        persp(PERSP_VIEW);
 
        glInitNames();
-       hits= selectprojektie(buffer, 0, 0, 0, 0);
+       hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
 
        /* See if there are any selected bones in this group */
        if (hits) {
index 50511a1f94f7b16e327a1ead7335f0e41c0457e2..766ddd440651e9ffb8e096cece615a0aae13a549 100644 (file)
@@ -245,7 +245,7 @@ void mouse_mball()
        int a, hits;
        unsigned int buffer[MAXPICKBUF];
        
-       hits= selectprojektie(buffer, 0, 0, 0, 0);
+       hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
 
        /* does startelem exist? */
        ml= editelems.first;
index c3f9f5e32431af15b1cd14dca01aba2850ac251b..26760c502529368bab38447fd43e48e61dc7b527 100644 (file)
@@ -39,6 +39,7 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+#include "MEM_guardedalloc.h"
 
 #include "IMB_imbuf.h"
 #include "PIL_time.h"
@@ -1057,8 +1058,8 @@ void mouse_select(void)
                }
        }
        else {
-               hits= selectprojektie(buffer, mval[0]-7, mval[1]-7, mval[0]+7, mval[1]+7);
-               if(hits==0) hits= selectprojektie(buffer, mval[0]-21, mval[1]-21, mval[0]+21, mval[1]+21);
+               hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-7, mval[1]-7, mval[0]+7, mval[1]+7);
+               if(hits==0) hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-21, mval[1]-21, mval[0]+21, mval[1]+21);
 
                if(hits>0) {
                        
@@ -1243,7 +1244,7 @@ void borderselect(void)
                if (G.obpose){
                        if(G.obpose->type==OB_ARMATURE) {
                                Bone    *bone;
-                               hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+                               hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
                                base= FIRSTBASE;
                                for (a=0; a<hits; a++){
                                        index = buffer[(4*a)+3];
@@ -1406,7 +1407,7 @@ void borderselect(void)
                                allqueue(REDRAWVIEW3D, 0);
                        }
                        else if(G.obedit->type==OB_MBALL) {
-                               hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+                               hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
                                
                                ml= editelems.first;
                                
@@ -1432,7 +1433,7 @@ void borderselect(void)
                        else if(G.obedit->type==OB_ARMATURE) {
                                EditBone *ebone;
 
-                               hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+                               hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
                                base= FIRSTBASE;
                                for (a=0; a<hits; a++){
@@ -1485,32 +1486,56 @@ void borderselect(void)
 
                }
                else {
-                       
-                       hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+                       unsigned int *vbuffer=NULL; /* selection buffer */
+                       unsigned int *col;                      /* color in buffer      */
+                       short selecting = 0;
+
+                       if (val==LEFTMOUSE)
+                               selecting = 1;
+
+                       vbuffer = MEM_mallocN(4 * G.totobj * sizeof(unsigned int), "selection buffer");
+                       hits= view3d_opengl_select(vbuffer, 4*G.totobj, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+                       /*
+                       LOGIC NOTES (theeth):
+                       The buffer and ListBase have the same relative order, which makes the selection
+                       very simple. Loop through both data sets at the same time, if the color
+                       is the same as the object, we have a hit and can move to the next color
+                       and object pair, if not, just move to the next object,
+                       keeping the same color until we have a hit.
+
+                       The buffer order is defined by OGL standard, hopefully no stupid GFX card
+                       does it incorrectly.
+                       */
+
+                       if (hits) { /* no need to loop if there's no hit */
+                               base= FIRSTBASE;
+                               col = vbuffer + 3;
+                               while(base && hits) {
+                                       Base *next = base->next;
+                                       if(base->lay & G.vd->lay) {
+                                               if (base->selcol == *col) {
+                                                       if (selecting)
+                                                               base->flag |= SELECT;
+                                                       else
+                                                               base->flag &= ~SELECT;
 
-                       base= FIRSTBASE;
-                       while(base) {
-                               if(base->lay & G.vd->lay) {
-                                       for(a=0; a<hits; a++) {
-                                               /* converted index */
-                                               if(base->selcol==buffer[ (4 * a) + 3 ]) {
-                                                       if(val==LEFTMOUSE) base->flag |= SELECT;
-                                                       else base->flag &= ~SELECT;
                                                        base->object->flag= base->flag;
 
-                                                       draw_object_ext(base);
-                                                       break;
+                                                       col+=4; /* next color */
+                                                       hits--;
                                                }
                                        }
+                                       
+                                       base= next;
                                }
-                               
-                               base= base->next;
                        }
                        /* frontbuffer flush */
                        glFlush();
+
+                       MEM_freeN(vbuffer);
                        
                        allqueue(REDRAWDATASELECT, 0);
-                       
+
                        /* because backbuf drawing */
                        tel= 1;
                        base= FIRSTBASE;
index 270754c925cdc4a53d22199ea4f38e0f4ee4f38c..98198fb4565118d43b5cdb612137d7178b401ebe 100644 (file)
@@ -857,7 +857,7 @@ void setcameratoview3d(void)
 }
 
 /* IGLuint-> GLuint*/
-short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2)
+short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
 {
        rctf rect;
        Base *base;
@@ -888,7 +888,7 @@ short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short
                glEnable(GL_DEPTH_TEST);
        }
 
-       glSelectBuffer( MAXPICKBUF, (GLuint *)buffer);
+       glSelectBuffer( bufsize, (GLuint *)buffer);
        glRenderMode(GL_SELECT);
        glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
        glPushName(-1);