3D view orbit option: Around Active
authorMartin Poirier <theeth@yahoo.com>
Wed, 6 Jul 2005 00:33:41 +0000 (00:33 +0000)
committerMartin Poirier <theeth@yahoo.com>
Wed, 6 Jul 2005 00:33:41 +0000 (00:33 +0000)
This fixes the active object in place when orbiting the view.
Choppy 15fps demo can be seen there: http://www.elysiun.com/~theeth/bf/around_active.html

Image Memory Grabage Collection
This adds memory handling to the image code. An image is tagged each time it is used.
During a collection cycle (frequency of cycles is user defined), if an image is older
than a user defined limit, its buffer gets deallocated. This also applies to gl memory buffers.
Images that are loading in GL memory needs to go through two time outs before being fully deallocated: the first time out deallocated the gl memorry, the second the buffer in ram.

Notes:
Image buffer loaded from python gets tagged as permanent upon load. That tag is removed when python stops using the image.
I might have missed some tagging spots, especially in the rendering pipeline. Someone with more knowledge about this code should check to be careful.
Tagging is done on every access, for rendering, this will probably be a performance hit. A scheme should be developped to only tag when the rendering is completed.
Collecting is called in draw_object, most likely not the best place to do it.
Safe from undo, since using undo deallocates memory anyway (like when loading a blend file with one currently opened)

Userpref DNA changes:
I've changed a couple of flagging variables from short to int. Some because they needed more space, others to keep SDNA happy.

Info window changes:
I've grouped a couple of buttons in aligned blocks and changed the color of mutually exclusive options to make them clearer.
Matt didn't do any changes on that in tuhopuu, so hopefully I'm not stepping on anyone's feet with this.

Also changed double constants into floats with f in a couple of places (mostly space.c) to make compiler happier.

15 files changed:
source/blender/blenkernel/BKE_image.h
source/blender/blenkernel/intern/image.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_image_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/python/api2_2x/Draw.c
source/blender/python/api2_2x/Image.c
source/blender/render/intern/source/pixelshading.c
source/blender/render/intern/source/texture.c
source/blender/src/drawimage.c
source/blender/src/drawmesh.c
source/blender/src/drawobject.c
source/blender/src/drawview.c
source/blender/src/space.c
source/blender/src/view.c

index 0ab8a6130b7ea028372e79807c3487bf423ce408..02892637443ef9268c0a139a6a7b0e7984a77dcb 100644 (file)
@@ -49,11 +49,17 @@ struct Image *add_image(char *name);
 void free_unused_animimages(void);
 
 void makepicstring(char *string, int frame);
+void addImageExtension(char *string);
+
 struct anim *openanim(char * name, int flags);
 void ima_ibuf_is_nul(struct Tex *tex, struct Image *ima);
 void load_image(struct Image * ima, int flags, char *relabase, int framenum);
 void converttopremul(struct ImBuf *ibuf);
 
+void tag_image_time(struct Image *ima);
+void free_old_images(void);
+
+
 #ifdef __cplusplus
 }
 #endif
index 051646f9ae360c63195ed38a65838011dc390aae..2975e592a7fc6f0d0ed356bac458d9bebec8e4db 100644 (file)
@@ -41,6 +41,8 @@
 #include <io.h>
 #endif
 
+#include <time.h>
+
 #include "MEM_guardedalloc.h"
 
 #include "IMB_imbuf_types.h"
@@ -49,6 +51,7 @@
 #include "DNA_image_types.h"
 #include "DNA_texture_types.h"
 #include "DNA_packedFile_types.h"
+#include "DNA_userdef_types.h"
 
 #include "BLI_blenlib.h"
 
@@ -143,6 +146,60 @@ Image *add_image(char *name)
        return ima;
 }
 
+void tag_image_time(Image *ima)
+{
+       if (ima)
+               ima->lastused = clock() / CLOCKS_PER_SEC;
+}
+
+void tag_all_images_time() {
+       Image *ima;
+       long ctime = clock() / CLOCKS_PER_SEC;
+
+       ima= G.main->image.first;
+       while(ima) {
+               if(ima->bindcode || ima->repbind || ima->ibuf) {
+                       ima->lastused = ctime;
+               }
+       }
+}
+
+void free_old_images()
+{
+       Image *ima;
+       static long lasttime = 0;
+       long ctime = clock() / CLOCKS_PER_SEC;
+       
+       /* 
+          Run garbage collector once for every collecting period of time 
+          if textimeout is 0, that's the option to NOT run the collector
+       */
+       if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
+               return;
+
+       lasttime = ctime;
+
+       ima= G.main->image.first;
+       while(ima) {
+               /* lastused == 0 is the tag for non removable images */
+               if(ima->flag & IMA_NOCOLLECT && ctime - ima->lastused > U.textimeout) {
+                       /*
+                          If it's in GL memory, deallocate and set time tag to current time
+                          This gives textures a "second chance" to be used before dying.
+                       */
+                       if(ima->bindcode || ima->repbind) {
+                               free_realtime_image(ima);
+                               ima->lastused = ctime;
+                       }
+                       /* Otherwise, just kill the buffers */
+                       else if (ima->ibuf) {
+                               free_image_buffers(ima);
+                       }
+               }
+               ima = ima->id.next;
+       }
+}
+
 void free_unused_animimages()
 {
        Image *ima, *nima;
@@ -209,6 +266,35 @@ void makepicstring(char *string, int frame)
                
 }
 
+void addImageExtension(char *string)
+{
+       char *extension;
+
+       if(G.scene->r.imtype== R_IRIS) {
+               extension= ".rgb";
+       }
+       else if(G.scene->r.imtype==R_IRIZ) {
+               extension= ".rgb";
+       }
+       else if(G.scene->r.imtype==R_PNG) {
+               extension= ".png";
+       }
+       else if(G.scene->r.imtype==R_TARGA) {
+               extension= ".tga";
+       }
+       else if(G.scene->r.imtype==R_RAWTGA) {
+               extension= ".tga";
+       }
+       else if(G.scene->r.imtype==R_JPEG90) {
+               extension= ".jpg";
+       }
+       else if(G.scene->r.imtype==R_BMP) {
+               extension= ".bmp";
+       }
+       strcat(string, extension);
+}
+
+
 /* ******** IMAGE WRAPPING INIT ************* */
 
 /* used by sequencer, texture */
@@ -437,13 +523,16 @@ void ima_ibuf_is_nul(Tex *tex, Image *ima)
                }
        }
        
-       if(ima->ibuf==0) ima->ok= 0;
+       if(ima->ibuf)
+               ima->lastused = clock() / CLOCKS_PER_SEC;
+       else
+               ima->ok= 0;
        
        for(a=0; a<BLI_ARRAY_NELEMS(ima->mipmap); a++) {
                if(ima->mipmap[a]) IMB_freeImBuf(ima->mipmap[a]);
                ima->mipmap[a]= 0;
        }
-       
+
 }
 
 
index 661a520832f97a440887cddbebee0f0bf033231d..fc89dff928a86c5ce535f66f0d369f3f2da38280 100644 (file)
@@ -4611,6 +4611,10 @@ static void do_versions(FileData *fd, Main *main)
                Camera *cam= main->camera.first;
                Material *ma;
                bScreen *sc;
+
+               /* GL Texture Garbage Collection */
+               U.texcollectrate = 60;
+               U.textimeout = 120;
                
                while(sce) {
                        sce->r.mode &= ~R_ZBLUR;        // disabled for release
index 256d69456e8e9f97933d431a67c0dc74f87c0cc7..7d35cf8c5f745a8493671df6fd5e91da852aee1a 100644 (file)
@@ -62,8 +62,10 @@ typedef struct Image {
        struct PackedFile * packedfile;
 
        float lastupdate;
+       long  lastused;
        short animspeed;
        short reserved1;
+       int   reserved2;
 } Image;
 
 /*  in Image struct */
@@ -77,6 +79,7 @@ typedef struct Image {
 #define IMA_FROMANIM   4
 #define IMA_USED               8
 #define        IMA_REFLECT             16
+#define IMA_NOCOLLECT   32
 
 /* tpageflag */
 #define IMA_TILES              1
index 51089cfc63698f73391743fa00fbe60801286920..f8a0d82037cc1d6333aa43c51585537bba8c5a4a 100644 (file)
@@ -125,7 +125,7 @@ typedef struct SolidLight {
 } SolidLight;
 
 typedef struct UserDef {
-       short flag, dupflag;
+       int flag, dupflag;
        int savetime;
        char tempdir[160];      // FILE_MAXDIR length
        char fontdir[160];
@@ -140,7 +140,7 @@ typedef struct UserDef {
        short versions, vrmlflag;       // tmp for export, will be replaced by strubi
        int gameflags;
        int wheellinescroll;
-       short uiflag, language;
+       int uiflag, language;
        short userpref, viewzoom;
        short console_buffer;   //console vars here for tuhopuu compat, --phase
        short console_out;
@@ -156,6 +156,7 @@ typedef struct UserDef {
        short tb_leftmouse, tb_rightmouse;
        struct SolidLight light[3];
        short tw_hotspot, tw_flag, tw_handlesize, tw_size;
+       long textimeout, texcollectrate;
 } UserDef;
 
 extern UserDef U; /* from usiblender.c !!!! */
@@ -200,6 +201,7 @@ extern UserDef U; /* from usiblender.c !!!! */
 #define USER_AUTOPERSP                 2048
 #define USER_LOCKAROUND        4096
 #define USER_GLOBALUNDO        8192
+#define USER_ORBIT_SELECTION   16384
 
 /* transopts */
 
index ec72394efc211d44aad3864a3bc8912744cec319..6e9c73faea44b4d7d740635c6ac52eb08477afe7 100644 (file)
@@ -1314,6 +1314,9 @@ static PyObject *Method_Image( PyObject * self, PyObject * args )
                return EXPP_ReturnPyObjError( PyExc_RuntimeError,
                        "couldn't load image data in Blender" );
 
+       /* Update the time tag of the image */
+       tag_image_time(image);
+
        /* set up a valid clipping rectangle.  if no clip rectangle was
         * given, this results in inclusion of the entire image.  otherwise,
         * the clipping is just checked against the bounds of the image.
index 1530eeb80a2e802b404e3bc8090607da022cfc7a..7b7bc61c983a79708fd0be63f5710d947c2b5699 100644 (file)
@@ -580,6 +580,8 @@ static PyObject *Image_glFree( BPy_Image * self )
        Image *img = self->image;
 
        free_realtime_image( img );
+       /* remove the nocollect flag, image is available for garbage collection again */
+       img->flag &= ~IMA_NOCOLLECT;
        return EXPP_incr_ret( Py_None );
 }
 
@@ -612,6 +614,11 @@ static PyObject *Image_glLoad( BPy_Image * self )
                glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, img->ibuf->x,
                              img->ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                              img->ibuf->rect );
+
+               /* raise the nocollect flag, image is not available for garbage collection 
+                  (python GL might use it directly)
+               */
+               img->flag |= IMA_NOCOLLECT;
        }
 
        return PyLong_FromUnsignedLong( img->bindcode );
index 0af4696eee095b03aee76be6411016da2ec5eef8..071f64fec70c2eef0fa35ae64e74950ac95612fe 100644 (file)
@@ -746,6 +746,8 @@ void fillBackgroundImageChar(char *col, float x, float y)
                return;
        }
 
+       tag_image_time(R.backbuf);
+
        /* Now for the real extraction: */
        /* Get the y-coordinate of the scanline? */
        iy= (int) ((y+R.afmy+R.ystart)*R.backbuf->ibuf->y)/(2*R.afmy);
index 7f02260bfd719392efd3c46cf2e9e4b96a416abe..191661d8ed72a1a763808e176d8aaee90f4b7c6d 100644 (file)
@@ -1173,6 +1173,7 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
        case TEX_IMAGE:
                if(osatex) retval= imagewraposa(tex, tex->ima, texvec, dxt, dyt, texres); 
                else retval= imagewrap(tex, tex->ima, texvec, texres); 
+               tag_image_time(tex->ima); /* tag image as having being used */
                break;
        case TEX_PLUGIN:
                retval= plugintex(tex, texvec, dxt, dyt, osatex, texres);
index efc2892c10690fbdded730cb7578028522f02ab9..afd98abe78f952f0354ce68477d06029cd09bf46 100644 (file)
@@ -826,10 +826,10 @@ void drawimagespace(ScrArea *sa, void *spacedata)
        what_image(G.sima);
        
        if(G.sima->image) {
-       
                if(G.sima->image->ibuf==0) {
                        load_image(G.sima->image, IB_rect, G.sce, G.scene->r.cfra);
                }       
+               tag_image_time(G.sima->image);
                ibuf= G.sima->image->ibuf;
        }
        
index bca1729cf6e2ad87befe5da77ef52c51f9ea3b58..de97ebc1edb36790da52fdcbf4e39807a2b35145 100644 (file)
@@ -289,7 +289,7 @@ int set_tpage(TFace *tface)
 
        if(ima->ibuf==0) {
                load_image(ima, IB_rect, G.sce, G.scene->r.cfra);
-               
+
                if(ima->ibuf==0) {
                        ima->ok= 0;
 
@@ -417,6 +417,8 @@ int set_tpage(TFace *tface)
        }
        else glBindTexture( GL_TEXTURE_2D, *bind);
        
+       tag_image_time(ima);
+
        glEnable(GL_TEXTURE_2D);
 
        fCurpage= ima;
index 65550172aec954ab7612cabd11523825ec8c4267..bcb13d391d0032bfd3b3c3505883c133afdbb093 100644 (file)
@@ -3840,6 +3840,8 @@ void draw_object(Base *base)
                glEnd();
                
        }
+
+       free_old_images();
 }
 
 void draw_object_ext(Base *base)
index fcbe2028300df300d0b4ee926eb9ffd683185580..738803161f35591f8cbf5880606b37f74a0bf803 100644 (file)
@@ -347,6 +347,8 @@ static void draw_bgpic(void)
        
        if(ima==0) return;
        if(ima->ok==0) return;
+
+       tag_image_time(ima);
        
        /* test for image */
        if(ima->ibuf==0) {
index 7e2cc16e77b277e39d61e1c3066730d49ccbad3b..0b29c47f2b1dd0a6ff3bc7b5c25296d2711fd782 100644 (file)
@@ -1850,9 +1850,9 @@ static void initview3d(ScrArea *sa)
        BLI_addhead(&sa->spacedata, vd);        /* addhead! not addtail */
 
        vd->spacetype= SPACE_VIEW3D;
-       vd->blockscale= 0.7;
-       vd->viewquat[0]= 1.0;
-       vd->viewquat[1]= vd->viewquat[2]= vd->viewquat[3]= 0.0;
+       vd->blockscale= 0.7f;
+       vd->viewquat[0]= 1.0f;
+       vd->viewquat[1]= vd->viewquat[2]= vd->viewquat[3]= 0.0f;
        vd->persp= 1;
        vd->drawtype= OB_WIRE;
        vd->view= 7;
@@ -1961,11 +1961,11 @@ static void winqreadipospace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        view2dmove(event);      /* in drawipo.c */
                        break;
                case PADPLUSKEY:
-                       view2d_zoom(v2d, 0.1154, sa->winx, sa->winy);
+                       view2d_zoom(v2d, 0.1154f, sa->winx, sa->winy);
                        doredraw= 1;
                        break;
                case PADMINUS:
-                       view2d_zoom(v2d, -0.15, sa->winx, sa->winy);
+                       view2d_zoom(v2d, -0.15f, sa->winx, sa->winy);
                        doredraw= 1;
                        break;
                case PAGEUPKEY:
@@ -2075,7 +2075,7 @@ void initipo(ScrArea *sa)
        BLI_addhead(&sa->spacedata, sipo);
 
        sipo->spacetype= SPACE_IPO;
-       sipo->blockscale= 0.7;
+       sipo->blockscale= 0.7f;
        
        /* sipo space loopt van (0,-?) tot (??,?) */
        sipo->v2d.tot.xmin= 0.0;
@@ -2279,10 +2279,10 @@ void drawinfospace(ScrArea *sa, void *spacedata)
 
        if(curarea->winx<=1280.0) {
                fac= ((float)curarea->winx)/1280.0f;
-               myortho2(0.375, 1280.375, 0.375, curarea->winy/fac + 0.375);
+               myortho2(0.375f, 1280.375f, 0.375f, curarea->winy/fac + 0.375f);
        }
        else {
-               myortho2(0.375, (float)curarea->winx + 0.375, 0.375, (float)curarea->winy + 0.375);
+               myortho2(0.375f, (float)curarea->winx + 0.375f, 0.375f, (float)curarea->winy + 0.375f);
        }
        
        sprintf(naam, "infowin %d", curarea->win);
@@ -2370,15 +2370,16 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                uiDefBut(block, LABEL,0,"Display:",
                        xpos,y6label,spref,buth,
                        0, 0, 0, 0, 0, "");     
-               uiDefButBitS(block, TOG, USER_TOOLTIPS, 0, "ToolTips",
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, USER_TOOLTIPS, 0, "ToolTips",
                        (xpos+edgsp),y5,spref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Display tooltips (help tags) over buttons");
-               uiDefButBitS(block, TOG, USER_DRAWVIEWINFO, B_DRAWINFO, "Object Info",
+               uiDefButBitI(block, TOG, USER_DRAWVIEWINFO, B_DRAWINFO, "Object Info",
                        (xpos+edgsp),y4,spref,buth,
                        &(U.uiflag), 0, 0, 0, 0,
                        "Display active object name and frame number in the 3D View");
-               uiDefButBitS(block, TOG, USER_SCENEGLOBAL, 0, "Global Scene",
+               uiDefButBitI(block, TOG, USER_SCENEGLOBAL, 0, "Global Scene",
                        (xpos+edgsp),y3,spref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Forces the current Scene to be displayed in all Screens");
@@ -2390,11 +2391,13 @@ void drawinfospace(ScrArea *sa, void *spacedata)
 #else 
                U.curssize=0; /*Small Cursor always for OS X for now */
 #endif
+               uiBlockEndAlign(block);
 
                uiDefBut(block, LABEL,0,"Menus:",
                        (xpos+(2*edgsp)+spref),y6label,spref,buth,
                        0, 0, 0, 0, 0, "");
-               uiDefButBitS(block, TOG, USER_MENUOPENAUTO, 0, "Open on Mouse Over",
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, USER_MENUOPENAUTO, 0, "Open on Mouse Over",
                        (xpos+edgsp+spref+midsp),y5,mpref,buth,
                        &(U.uiflag), 0, 0, 0, 0,
                        "Open menu buttons and pulldowns automatically when the mouse is hovering");
@@ -2406,10 +2409,12 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(2*spref)+(2*midsp)-edgsp),y4,spref+edgsp,buth,
                        &(U.menuthreshold2), 1, 40, 0, 0,
                        "Time delay in 1/10 seconds before automatically opening menu sublevels");
+               uiBlockEndAlign(block);
 
                uiDefBut(block, LABEL,0,"Toolbox click-hold delay:",
                        (xpos+(2*edgsp)+spref),y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
+               uiBlockBeginAlign(block);
                uiDefButS(block, NUM, 0, "LMB:",
                        (xpos+edgsp+spref+midsp),y2,spref+edgsp,buth,
                        &(U.tb_leftmouse), 2, 40, 0, 0,
@@ -2418,37 +2423,41 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(2*spref)+(2*midsp)-edgsp),y2,spref+edgsp,buth,
                        &(U.tb_rightmouse), 2, 40, 0, 0,
                        "Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox");      
-               uiDefButBitS(block, TOG, USER_PANELPINNED, 0, "Pin Floating Panels",
-                       (xpos+edgsp+spref+midsp),y1,mpref,buth,
+               uiBlockEndAlign(block);
+
+               uiDefButBitI(block, TOG, USER_PANELPINNED, 0, "Pin Floating Panels",
+                       (xpos+edgsp+spref+midsp),y1,(mpref/2),buth,
                        &(U.uiflag), 0, 0, 0, 0,
                        "Make floating panels invoked by a hotkey (eg. N Key) open at the previous location");
                
+               uiDefButBitI(block, TOG, USER_LOCKAROUND, B_DRAWINFO, "Global Pivot",
+                       (xpos+edgsp+spref+midsp+(mpref/2)),y1,(mpref/2),buth,
+                       &(U.uiflag), 0, 0, 0, 0,
+                       "Lock the same rotation/scaling pivot in all 3D Views");        
                
                uiDefBut(block, LABEL,0,"Snap to grid:",
                        (xpos+(2*edgsp)+spref+midsp+mpref),y6label,mpref,buth,
                        0, 0, 0, 0, 0, "");
-               uiDefButBitS(block, TOG, USER_AUTOGRABGRID, 0, "Grab/Move",
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, USER_AUTOGRABGRID, 0, "Grab/Move",
                        (xpos+edgsp+mpref+spref+(2*midsp)),y5,spref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Snap objects and sub-objects to grid units when moving");
-               uiDefButBitS(block, TOG, USER_AUTOROTGRID, 0, "Rotate",
+               uiDefButBitI(block, TOG, USER_AUTOROTGRID, 0, "Rotate",
                        (xpos+edgsp+mpref+spref+(2*midsp)),y4,spref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Snap objects and sub-objects to grid units when rotating");
-               uiDefButBitS(block, TOG, USER_AUTOSIZEGRID, 0, "Scale",
+               uiDefButBitI(block, TOG, USER_AUTOSIZEGRID, 0, "Scale",
                        (xpos+edgsp+mpref+spref+(2*midsp)),y3,spref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Snap objects and sub-objects to grid units when scaling");
-               
-               uiDefButBitS(block, TOG, USER_LOCKAROUND, B_DRAWINFO, "Global Pivot",
-                       (xpos+edgsp+mpref+spref+(2*midsp)),y1,spref,buth,
-                       &(U.uiflag), 0, 0, 0, 0,
-                       "Lock the same rotation/scaling pivot in all 3D Views");        
+               uiBlockEndAlign(block);
                
                uiDefBut(block, LABEL,0,"View zoom:",
                        (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y6label,mpref,buth,
                        0, 0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
+               uiBlockSetCol(block, TH_BUT_SETTING1);  /* mutually exclusive toggles, start color */
                uiDefButS(block, ROW, 0, "Continue",
                        (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y5,(mpref/3),buth,
                        &(U.viewzoom), 40, USER_ZOOM_CONT, 0, 0,
@@ -2461,37 +2470,45 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(2*mpref/3)),y5,(mpref/3),buth,
                        &(U.viewzoom), 40, USER_ZOOM_SCALE, 0, 0,
                        "Zooms in and out like scaling the view, mouse movements relative to center.");
+               uiBlockSetCol(block, TH_AUTO);                  /* end color */
                uiBlockEndAlign(block);
                
                uiDefBut(block, LABEL,0,"View rotation:",
                        (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y4label,mpref,buth,
                        0, 0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
-               uiDefButBitS(block, TOG, USER_TRACKBALL, B_DRAWINFO, "Trackball",
+               uiBlockSetCol(block, TH_BUT_SETTING1);  /* mutually exclusive toggles, start color */
+               uiDefButBitI(block, TOG, USER_TRACKBALL, B_DRAWINFO, "Trackball",
                        (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y3,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Allow the view to tumble freely when orbiting with the Middle Mouse Button");
-               uiDefButBitS(block, TOGN, USER_TRACKBALL, B_DRAWINFO, "Turntable",
+               uiDefButBitI(block, TOGN, USER_TRACKBALL, B_DRAWINFO, "Turntable",
                        (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y3,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0,
-                       "Keep the Global Z axis pointing upwards when orbiting the view with the Middle Mouse Button");
-               uiBlockEndAlign(block);
-               
-               uiDefButBitS(block, TOG, USER_AUTOPERSP, B_DRAWINFO, "Auto Perspective",
-                       (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y1,spref,buth,
+                       "Allow the view to tumble freely when orbiting with the Middle Mouse Button");
+               uiBlockSetCol(block, TH_AUTO);                  /* end color */
+               uiDefButBitI(block, TOG, USER_AUTOPERSP, B_DRAWINFO, "Auto Perspective",
+                       (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y2,(mpref/2),buth,
                        &(U.uiflag), 0, 0, 0, 0,
                        "Automatically switch between orthographic and perspective when changing from top/front/side views");
+               uiDefButBitI(block, TOG, USER_ORBIT_SELECTION, B_DRAWINFO, "Around Active",
+                       (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y2,(mpref/2),buth,
+                       &(U.uiflag), 0, 0, 0, 0,
+                       "Keep the active object in place when orbiting the views (Object Mode)");
+               uiBlockEndAlign(block);
 
                uiDefBut(block, LABEL,0,"Select with:",
                        (xpos+(2*edgsp)+(3*mpref)+(3*midsp)),y6label,mpref,buth,
                        0, 0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
-               uiDefButBitS(block, TOG, USER_LMOUSESELECT, B_DRAWINFO, "Left Mouse",
+               uiBlockSetCol(block, TH_BUT_SETTING1);  /* mutually exclusive toggles, start color */
+               uiDefButBitI(block, TOG, USER_LMOUSESELECT, B_DRAWINFO, "Left Mouse",
                        (xpos+edgsp+(3*mpref)+(4*midsp)),y5,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Use the Left Mouse Button for selection");
-               uiDefButBitS(block, TOGN, USER_LMOUSESELECT, B_DRAWINFO, "Right Mouse",
+               uiDefButBitI(block, TOGN, USER_LMOUSESELECT, B_DRAWINFO, "Right Mouse",
                        (xpos+edgsp+(3*mpref)+(4*midsp)+(mpref/2)),y5,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Use the Right Mouse Button for selection");
+               uiBlockSetCol(block, TH_AUTO);                  /* end color */
                uiBlockEndAlign(block);
                
                
@@ -2509,7 +2526,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                if (U.flag & USER_LMOUSESELECT) 
                        U.flag &= ~USER_TWOBUTTONMOUSE;
                
-               uiDefButBitS(block, TOG, USER_TWOBUTTONMOUSE, B_DRAWINFO, "Emulate 3 Button Mouse",
+               uiDefButBitI(block, TOG, USER_TWOBUTTONMOUSE, B_DRAWINFO, "Emulate 3 Button Mouse",
                        (xpos+edgsp+(3*mpref)+(4*midsp)),y3,mpref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Emulates Middle Mouse with Alt+LeftMouse (doesnt work with Left Mouse Select option)");
@@ -2519,18 +2536,21 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+(2*edgsp)+(4*mpref)+(4*midsp)),y6label,mpref,buth,
                        0, 0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
-               uiDefButBitS(block, TOGN, USER_VIEWMOVE, B_DRAWINFO, "Rotate View",
+               uiBlockSetCol(block, TH_BUT_SETTING1);  /* mutually exclusive toggles, start color */
+               uiDefButBitI(block, TOGN, USER_VIEWMOVE, B_DRAWINFO, "Rotate View",
                        (xpos+edgsp+(4*mpref)+(5*midsp)),y5,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Default action for the Middle Mouse Button");
-               uiDefButBitS(block, TOG, USER_VIEWMOVE, B_DRAWINFO, "Pan View",
+               uiDefButBitI(block, TOG, USER_VIEWMOVE, B_DRAWINFO, "Pan View",
                        (xpos+edgsp+(4*mpref)+(5*midsp)+(mpref/2)),y5,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Default action for the Middle Mouse Button");
+               uiBlockSetCol(block, TH_AUTO);                  /* end color */
                uiBlockEndAlign(block);
                        
                uiDefBut(block, LABEL,0,"Mouse Wheel:",
                        (xpos+(2*edgsp)+(4*mpref)+(4*midsp)),y4label,mpref,buth,
                        0, 0, 0, 0, 0, "");
-               uiDefButBitS(block, TOG, USER_WHEELZOOMDIR, 0, "Invert Zoom",
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, USER_WHEELZOOMDIR, 0, "Invert Zoom",
                        (xpos+edgsp+(4*mpref)+(5*midsp)),y3,spref,buth,
                        &(U.uiflag), 0, 0, 0, 0,
                        "Swap the Mouse Wheel zoom direction");
@@ -2538,6 +2558,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(4*mpref)+(6*midsp)+spref-edgsp),y3,spref+edgsp,buth,
                        &U.wheellinescroll, 0.0, 32.0, 0, 0,
                        "The number of lines scrolled at a time with the mouse wheel"); 
+               uiBlockEndAlign(block);
 
 
                uiDefBut(block, LABEL,0,"3D Transform Widget:",
@@ -2563,10 +2584,10 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        xpos,y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
-               uiDefButBitS(block, TOGN, USER_MAT_ON_OB, B_DRAWINFO, "ObData",
+               uiDefButBitI(block, TOGN, USER_MAT_ON_OB, B_DRAWINFO, "ObData",
                        (xpos+edgsp),y2,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Link new objects' material to the obData block");
-               uiDefButBitS(block, TOG, USER_MAT_ON_OB, B_DRAWINFO, "Object",
+               uiDefButBitI(block, TOG, USER_MAT_ON_OB, B_DRAWINFO, "Object",
                        (xpos+edgsp+(mpref/2)),y2,(mpref/2),buth,
                        &(U.flag), 0, 0, 0, 0, "Link new objects' material to the object block");
                uiBlockEndAlign(block);
@@ -2575,13 +2596,15 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                uiDefBut(block, LABEL,0,"Editmode undo:",
                        (xpos+(2*edgsp)+mpref),y3label, mpref,buth,
                        0, 0, 0, 0, 0, "");
+               uiBlockBeginAlign(block);
                uiDefButS(block, NUMSLI, B_DRAWINFO, "Steps:",
                        (xpos+edgsp+mpref+midsp),y2,mpref,buth,
                        &(U.undosteps), 2, 64, 0, 0, "Number of undo steps available in Edit Mode (smaller values conserve memory)");
 
-               uiDefButBitS(block, TOG, USER_GLOBALUNDO, B_DRAWINFO, "Global undo",
+               uiDefButBitI(block, TOG, USER_GLOBALUNDO, B_DRAWINFO, "Global undo",
                        (xpos+edgsp+mpref+midsp),y1,mpref,buth,
                        &(U.uiflag), 2, 64, 0, 0, "");
+               uiBlockEndAlign(block);
 
 
                uiDefBut(block, LABEL,0,"Auto keyframe",
@@ -2603,40 +2626,39 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+(2*edgsp)+(3*midsp)+(3*mpref)+spref),y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
 
-               uiDefButBitS(block, TOG, USER_DUP_MESH, 0, "Mesh",
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, USER_DUP_MESH, 0, "Mesh",
                        (xpos+edgsp+(4*midsp)+(3*mpref)+spref),y2,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes mesh data to be duplicated with Shift+D");
-               uiDefButBitS(block, TOG, USER_DUP_ARM, 0, "Armature",
-                       (xpos+edgsp+(4*midsp)+(3*mpref)+spref),y1,(spref+edgsp),buth,
-                       &(U.dupflag), 0, 0, 0, 0, "Causes armature data to be duplicated with Shift+D");
-
-               uiDefButBitS(block, TOG, USER_DUP_SURF, 0, "Surface",
+               uiDefButBitI(block, TOG, USER_DUP_SURF, 0, "Surface",
                        (xpos+edgsp+(5*midsp)+(3*mpref)+(2*spref)),y2,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes surface data to be duplicated with Shift+D");
-               uiDefButBitS(block, TOG, USER_DUP_LAMP, 0, "Lamp",
-                       (xpos+edgsp+(5*midsp)+(3*mpref)+(2*spref)),y1,(spref+edgsp),buth,
-                       &(U.dupflag), 0, 0, 0, 0, "Causes lamp data to be duplicated with Shift+D");
-
-               uiDefButBitS(block, TOG, USER_DUP_CURVE, 0, "Curve",
+               uiDefButBitI(block, TOG, USER_DUP_CURVE, 0, "Curve",
                        (xpos+edgsp+(6*midsp)+(3*mpref)+(3*spref)),y2,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes curve data to be duplicated with Shift+D");
-               uiDefButBitS(block, TOG, USER_DUP_MAT, 0, "Material",
-                       (xpos+edgsp+(6*midsp)+(3*mpref)+(3*spref)),y1,(spref+edgsp),buth,
-                       &(U.dupflag), 0, 0, 0, 0, "Causes material data to be duplicated with Shift+D");
-
-               uiDefButBitS(block, TOG, USER_DUP_FONT, 0, "Text",
+               uiDefButBitI(block, TOG, USER_DUP_FONT, 0, "Text",
                        (xpos+edgsp+(7*midsp)+(3*mpref)+(4*spref)),y2,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes text data to be duplicated with Shift+D");
-               uiDefButBitS(block, TOG, USER_DUP_TEX, 0, "Texture",
-                       (xpos+edgsp+(7*midsp)+(3*mpref)+(4*spref)),y1,(spref+edgsp),buth,
-                       &(U.dupflag), 0, 0, 0, 0, "Causes texture data to be duplicated with Shift+D");
-
-               uiDefButBitS(block, TOG, USER_DUP_MBALL, 0, "Metaball",
+               uiDefButBitI(block, TOG, USER_DUP_MBALL, 0, "Metaball",
                        (xpos+edgsp+(8*midsp)+(3*mpref)+(5*spref)),y2,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes metaball data to be duplicated with Shift+D");
-               uiDefButBitS(block, TOG, USER_DUP_IPO, 0, "Ipo",
+
+               uiDefButBitI(block, TOG, USER_DUP_ARM, 0, "Armature",
+                       (xpos+edgsp+(4*midsp)+(3*mpref)+spref),y1,(spref+edgsp),buth,
+                       &(U.dupflag), 0, 0, 0, 0, "Causes armature data to be duplicated with Shift+D");
+               uiDefButBitI(block, TOG, USER_DUP_LAMP, 0, "Lamp",
+                       (xpos+edgsp+(5*midsp)+(3*mpref)+(2*spref)),y1,(spref+edgsp),buth,
+                       &(U.dupflag), 0, 0, 0, 0, "Causes lamp data to be duplicated with Shift+D");
+               uiDefButBitI(block, TOG, USER_DUP_MAT, 0, "Material",
+                       (xpos+edgsp+(6*midsp)+(3*mpref)+(3*spref)),y1,(spref+edgsp),buth,
+                       &(U.dupflag), 0, 0, 0, 0, "Causes material data to be duplicated with Shift+D");
+               uiDefButBitI(block, TOG, USER_DUP_TEX, 0, "Texture",
+                       (xpos+edgsp+(7*midsp)+(3*mpref)+(4*spref)),y1,(spref+edgsp),buth,
+                       &(U.dupflag), 0, 0, 0, 0, "Causes texture data to be duplicated with Shift+D");
+               uiDefButBitI(block, TOG, USER_DUP_IPO, 0, "Ipo",
                        (xpos+edgsp+(8*midsp)+(3*mpref)+(5*spref)),y1,(spref+edgsp),buth,
                        &(U.dupflag), 0, 0, 0, 0, "Causes ipo data to be duplicated with Shift+D");
+               uiBlockEndAlign(block);
        
        } else if(U.userpref == 2) { /* language & colors */
 
@@ -2691,7 +2713,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                                (xpos+edgsp+(2.2*mpref)+(5*midsp)+(2*spref)),y1,spref,buth,
                                &(U.transopts), 0, 0, 0, 0, "Translate toolbox menu");
 
-                       uiDefButS(block, MENU|SHO, B_SETLANGUAGE, language_pup(),
+                       uiDefButI(block, MENU|SHO, B_SETLANGUAGE, language_pup(),
                                (xpos+edgsp+(2.2*mpref)+(3*midsp)),y2,mpref+(0.5*mpref)+3,buth,
                                &U.language, 0, 0, 0, 0, "Select interface language");
                                
@@ -2712,7 +2734,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        &U.versions, 0.0, 32.0, 0, 0,
                        "The number of old versions to maintain in the current directory, when manually saving");
 
-               uiDefButBitS(block, TOG, USER_AUTOSAVE, B_RESETAUTOSAVE, "Auto Save Temp Files",
+               uiDefButBitI(block, TOG, USER_AUTOSAVE, B_RESETAUTOSAVE, "Auto Save Temp Files",
                        (xpos+edgsp+mpref+midsp),y3,mpref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Enables automatic saving of temporary files");
@@ -2805,7 +2827,7 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(1*midsp)+(1*mpref)),y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
 
-               uiDefButBitS(block, TOG, USER_ALLWINCODECS, 0, "Enable all codecs",
+               uiDefButBitI(block, TOG, USER_ALLWINCODECS, 0, "Enable all codecs",
                        (xpos+edgsp+(1*mpref)+(1*midsp)),y2,mpref,buth,
                        &(U.uiflag), 0, 0, 0, 0, "Allows all codecs for rendering (not guaranteed)");
 #endif
@@ -2814,12 +2836,12 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(3*midsp)+(3*mpref)),y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
 
-               uiDefButBitS(block, TOG, USER_NO_CAPSLOCK, B_U_CAPSLOCK, "Disable Caps Lock",
+               uiDefButBitI(block, TOG, USER_NO_CAPSLOCK, B_U_CAPSLOCK, "Disable Caps Lock",
                        (xpos+edgsp+(3*midsp)+(3*mpref)),y1,mpref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Disables the Caps Lock key when entering text");
 
-               uiDefButBitS(block, TOG, USER_NONUMPAD, 0, "Emulate Numpad",
+               uiDefButBitI(block, TOG, USER_NONUMPAD, 0, "Emulate Numpad",
                        (xpos+edgsp+(3*midsp)+(3*mpref)),y2,mpref,buth,
                        &(U.flag), 0, 0, 0, 0,
                        "Causes the 1 to 0 keys to act as the numpad (useful for laptops)");
@@ -2833,23 +2855,29 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(4*mpref)+(4*midsp)),y2,mpref,buth,
                        &(U.gameflags), 0, 0, 0, 0, "Disables sounds from being played in games");
 
-               uiDefButBitS(block, TOG, USER_FILTERFILEEXTS, 0, "Filter File Extensions",
+               uiDefButBitI(block, TOG, USER_FILTERFILEEXTS, 0, "Filter File Extensions",
                        (xpos+edgsp+(4*mpref)+(4*midsp)),y1,mpref,buth,
                        &(U.uiflag), 0, 0, 0, 0, "Display only files with extensions in the image select window");
 
 
                uiDefBut(block, LABEL,0,"OpenGL:",
-                       (xpos+edgsp+(5*midsp)+(5*mpref)),y3label,mpref,buth,
+                       (xpos+edgsp+(5*midsp)+(5*mpref)),y5label,mpref,buth,
                        0, 0, 0, 0, 0, "");
-
                uiDefButBitI(block, TOGN, USER_DISABLE_MIPMAP, B_MIPMAPCHANGED, "Mipmaps",
-                       (xpos+edgsp+(5*mpref)+(5*midsp)),y2,mpref,buth,
+                       (xpos+edgsp+(5*mpref)+(5*midsp)),y4,mpref,buth,
                        &(U.gameflags), 0, 0, 0, 0, "Toggles between mipmap textures on (beautiful) and off (fast)");
-
                uiDefButBitI(block, TOG, USER_VERTEX_ARRAYS, 0, "Vertex Arrays",
-                       (xpos+edgsp+(5*mpref)+(5*midsp)),y1,mpref,buth,
+                       (xpos+edgsp+(5*mpref)+(5*midsp)),y3,mpref,buth,
                        &(U.gameflags), 0, 0, 0, 0, "Toggles between vertex arrays on (less reliable) and off (more reliable)");
 
+               uiDefButI(block, NUM, 0, "Time Out ",
+                       (xpos+edgsp+(5*mpref)+(5*midsp)), y2, mpref, buth, 
+                       &U.textimeout, 0.0, 3600.0, 30, 2, "Time since last access of a GL texture in seconds after which it is freed. (Set to 0 to keep textures allocated)");
+               uiDefButI(block, NUM, 0, "Collect Rate ",
+                       (xpos+edgsp+(5*mpref)+(5*midsp)), y1, mpref, buth, 
+                       &U.texcollectrate, 1.0, 3600.0, 30, 2, "Number of seconds between each run of the GL texture garbage collector.");
+
+
                uiDefBut(block, LABEL,0,"Audio mixing buffer:",
                        (xpos+edgsp+(2*midsp)+(2*mpref)),y3label,mpref,buth,
                        0, 0, 0, 0, 0, "");
@@ -3177,9 +3205,9 @@ void set_rects_butspace(SpaceButs *buts)
 void test_butspace(void)
 {
        ScrArea *area= curarea;
-       int blocksmin= uiBlocksGetYMin(&area->uiblocks)-10.0;
+       int blocksmin= uiBlocksGetYMin(&area->uiblocks)-10.0f;
        
-       G.buts->v2d.tot.ymin= MIN2(0.0, blocksmin-10.0);
+       G.buts->v2d.tot.ymin= MIN2(0.0f, blocksmin-10.0f);
 }
 
 static void init_butspace(ScrArea *sa)
@@ -3335,7 +3363,7 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        }
                        else {
                                if((G.qual==0)) {
-                                       dx= 0.1154*(v2d->cur.xmax-v2d->cur.xmin);
+                                       dx= 0.1154f*(v2d->cur.xmax-v2d->cur.xmin);
                                        v2d->cur.xmin+= dx;
                                        v2d->cur.xmax-= dx;
                                        test_view2d(G.v2d, curarea->winx, curarea->winy);
@@ -3362,7 +3390,7 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                if((G.qual==LR_SHIFTKEY))
                                        no_gaps();
                                else if((G.qual==0)) {
-                                       dx= 0.15*(v2d->cur.xmax-v2d->cur.xmin);
+                                       dx= 0.15f*(v2d->cur.xmax-v2d->cur.xmin);
                                        v2d->cur.xmin-= dx;
                                        v2d->cur.xmax+= dx;
                                        test_view2d(G.v2d, curarea->winx, curarea->winy);
index 9f30306d398989f1ac4b9e320b583fb3944e3194..270754c925cdc4a53d22199ea4f38e0f4ee4f38c 100644 (file)
@@ -432,10 +432,13 @@ void calctrackballvec(rcti *area, short *mval, float *vec)
 
 void viewmove(int mode)
 {
+       Object *ob = OBACT;
        float firstvec[3], newvec[3], dvec[3];
        float oldquat[4], q1[4], si, phi, dist0;
+       float ofs[3], obofs[3];
        int firsttime=1;
        short mvalball[2], mval[2], mvalo[2];
+       short use_sel = 0;
        
        /* sometimes this routine is called from headerbuttons */
        areawinset(curarea->win);
@@ -453,6 +456,19 @@ void viewmove(int mode)
 
        /* cumultime(0); */
 
+       if (G.obedit==0 && G.obpose==0 && U.uiflag & USER_ORBIT_SELECTION) {
+               use_sel = 1;
+               VECCOPY(ofs, G.vd->ofs);
+               if (ob) {
+                       obofs[0] = -ob->obmat[3][0];
+                       obofs[1] = -ob->obmat[3][1];
+                       obofs[2] = -ob->obmat[3][2];
+               }
+               else {
+                       VECCOPY(obofs, ofs);
+               }
+       }
+
        while(TRUE) {
                getmouseco_sc(mval);
                
@@ -510,8 +526,21 @@ void viewmove(int mode)
                                        q1[0]= cos(phi);
                                        q1[1]*= si;
                                        q1[2]*= si;
-                                       q1[3]*= si;                                             
+                                       q1[3]*= si;     
                                        QuatMul(G.vd->viewquat, q1, oldquat);
+
+                                       if (use_sel) {
+                                               /* compute the post multiplication quat, to rotate the offset correctly */
+                                               QUATCOPY(q1, oldquat);
+                                               QuatConj(q1);
+                                               QuatMul(q1, q1, G.vd->viewquat);
+
+                                               QuatConj(q1); /* conj == inv for unit quat */
+                                               VECCOPY(G.vd->ofs, ofs);
+                                               VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+                                               QuatMulVecf(q1, G.vd->ofs);
+                                               VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+                                       }
                                } else {
                                        /* New turntable view code by John Aughey */
 
@@ -541,12 +570,26 @@ void viewmove(int mode)
                                        q1[3] = si * xvec[2];
                                        QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
 
+                                       if (use_sel) {
+                                               QuatConj(q1); /* conj == inv for unit quat */
+                                               VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+                                               QuatMulVecf(q1, G.vd->ofs);
+                                               VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+                                       }
+
                                        /* Perform the orbital rotation */
                                        phi = sensitivity * (mval[0] - mvalo[0]);
                                        q1[0] = cos(phi);
                                        q1[1] = q1[2] = 0.0;
                                        q1[3] = sin(phi);
                                        QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
+
+                                       if (use_sel) {
+                                               QuatConj(q1);
+                                               VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+                                               QuatMulVecf(q1, G.vd->ofs);
+                                               VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+                                       }
                                }
                        }
                        else if(mode==1) {      /* translate */