Blender V2.61 - r43446

wm_subwindow.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): 2007 Blender Foundation (refactor)
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  *
00025  *
00026  * Subwindow opengl handling. 
00027  * BTW: subwindows open/close in X11 are way too slow, tried it, and choose for my own system... (ton)
00028  * 
00029  */
00030 
00036 #include <string.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_windowmanager_types.h"
00041 #include "DNA_screen_types.h"
00042 
00043 #include "BLI_blenlib.h"
00044 #include "BLI_math.h"
00045 #include "BLI_utildefines.h"
00046 
00047 
00048 #include "BKE_context.h"
00049 #include "BKE_global.h"
00050 
00051 #include "BIF_gl.h"
00052 
00053 #include "GPU_extensions.h"
00054 
00055 #include "WM_api.h"
00056 #include "wm_subwindow.h"
00057 #include "wm_window.h"
00058 
00059 /* wmSubWindow stored in wmWindow... but not exposed outside this C file */
00060 /* it seems a bit redundant (area regions can store it too, but we keep it
00061    because we can store all kind of future opengl fanciness here */
00062 
00063 /* we use indices and array because:
00064    - index has safety, no pointers from this C file hanging around
00065    - fast lookups of indices with array, list would give overhead
00066    - old code used it this way...
00067    - keep option open to have 2 screens using same window
00068 */
00069 
00070 typedef struct wmSubWindow {
00071     struct wmSubWindow *next, *prev;
00072     
00073     rcti winrct;
00074     int swinid;
00075 } wmSubWindow;
00076 
00077 
00078 /* ******************* open, free, set, get data ******************** */
00079 
00080 /* not subwindow itself */
00081 static void wm_subwindow_free(wmSubWindow *UNUSED(swin))
00082 {
00083     /* future fancy stuff */
00084 }
00085 
00086 void wm_subwindows_free(wmWindow *win)
00087 {
00088     wmSubWindow *swin;
00089     
00090     for(swin= win->subwindows.first; swin; swin= swin->next)
00091         wm_subwindow_free(swin);
00092     
00093     BLI_freelistN(&win->subwindows);
00094 }
00095 
00096 
00097 int wm_subwindow_get(wmWindow *win) 
00098 {
00099     if(win->curswin)
00100         return win->curswin->swinid;
00101     return 0;
00102 }
00103 
00104 static wmSubWindow *swin_from_swinid(wmWindow *win, int swinid)
00105 {
00106     wmSubWindow *swin;
00107     
00108     for(swin= win->subwindows.first; swin; swin= swin->next)
00109         if(swin->swinid==swinid)
00110             break;
00111     return swin;
00112 }
00113 
00114 void wm_subwindow_getsize(wmWindow *win, int swinid, int *x, int *y) 
00115 {
00116     wmSubWindow *swin= swin_from_swinid(win, swinid);
00117 
00118     if(swin) {
00119         *x= swin->winrct.xmax - swin->winrct.xmin + 1;
00120         *y= swin->winrct.ymax - swin->winrct.ymin + 1;
00121     }
00122 }
00123 
00124 void wm_subwindow_getorigin(wmWindow *win, int swinid, int *x, int *y)
00125 {
00126     wmSubWindow *swin= swin_from_swinid(win, swinid);
00127 
00128     if(swin) {
00129         *x= swin->winrct.xmin;
00130         *y= swin->winrct.ymin;
00131     }
00132 }
00133 
00134 void wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[][4])
00135 {
00136     wmSubWindow *swin= swin_from_swinid(win, swinid);
00137 
00138     if(swin) {
00139         /* used by UI, should find a better way to get the matrix there */
00140         if(swinid == win->screen->mainwin) {
00141             int width, height;
00142 
00143             wm_subwindow_getsize(win, swin->swinid, &width, &height);
00144             orthographic_m4(mat, -0.375f, (float)width-0.375f, -0.375f, (float)height-0.375f, -100, 100);
00145         }
00146         else
00147             glGetFloatv(GL_PROJECTION_MATRIX, (float*)mat);
00148     }
00149 }
00150 
00151 /* always sets pixel-precise 2D window/view matrices */
00152 /* coords is in whole pixels. xmin = 15, xmax= 16: means window is 2 pix big */
00153 int wm_subwindow_open(wmWindow *win, rcti *winrct)
00154 {
00155     wmSubWindow *swin;
00156     int width, height;
00157     int freewinid= 1;
00158     
00159     for(swin= win->subwindows.first; swin; swin= swin->next)
00160         if(freewinid <= swin->swinid)
00161             freewinid= swin->swinid+1;
00162 
00163     win->curswin= swin= MEM_callocN(sizeof(wmSubWindow), "swinopen");
00164     BLI_addtail(&win->subwindows, swin);
00165     
00166     if(G.f & G_DEBUG) printf("swin %d added\n", freewinid);
00167     swin->swinid= freewinid;
00168     swin->winrct= *winrct;
00169 
00170     /* and we appy it all right away */
00171     wmSubWindowSet(win, swin->swinid);
00172     
00173     /* extra service */
00174     wm_subwindow_getsize(win, swin->swinid, &width, &height);
00175     wmOrtho2(-0.375f, (float)width-0.375f, -0.375f, (float)height-0.375f);
00176     glLoadIdentity();
00177 
00178     return swin->swinid;
00179 }
00180 
00181 
00182 void wm_subwindow_close(wmWindow *win, int swinid)
00183 {
00184     wmSubWindow *swin= swin_from_swinid(win, swinid);
00185 
00186     if (swin) {
00187         if (swin==win->curswin)
00188             win->curswin= NULL;
00189         wm_subwindow_free(swin);
00190         BLI_remlink(&win->subwindows, swin);
00191         MEM_freeN(swin);
00192     } 
00193     else {
00194         printf("wm_subwindow_close: Internal error, bad winid: %d\n", swinid);
00195     }
00196 
00197 }
00198 
00199 /* pixels go from 0-99 for a 100 pixel window */
00200 void wm_subwindow_position(wmWindow *win, int swinid, rcti *winrct)
00201 {
00202     wmSubWindow *swin= swin_from_swinid(win, swinid);
00203     
00204     if(swin) {
00205         int width, height;
00206         
00207         swin->winrct= *winrct;
00208         
00209         /* CRITICAL, this clamping ensures that
00210             * the viewport never goes outside the screen
00211             * edges (assuming the x, y coords aren't
00212                      * outside). This caused a hardware lock
00213             * on Matrox cards if it happens.
00214             * 
00215             * Really Blender should never _ever_ try
00216             * to do such a thing, but just to be safe
00217             * clamp it anyway (or fix the bScreen
00218             * scaling routine, and be damn sure you
00219             * fixed it). - zr  (2001!)
00220             */
00221         
00222         if (swin->winrct.xmax > win->sizex)
00223             swin->winrct.xmax= win->sizex;
00224         if (swin->winrct.ymax > win->sizey)
00225             swin->winrct.ymax= win->sizey;
00226         
00227         /* extra service */
00228         wmSubWindowSet(win, swinid);
00229         wm_subwindow_getsize(win, swinid, &width, &height);
00230         wmOrtho2(-0.375f, (float)width-0.375f, -0.375f, (float)height-0.375f);
00231     }
00232     else {
00233         printf("wm_subwindow_position: Internal error, bad winid: %d\n", swinid);
00234     }
00235 }
00236 
00237 /* ---------------- WM versions of OpenGL calls, using glBlah() syntax ------------------------ */
00238 /* ----------------- exported in WM_api.h ------------------------------------------------------ */
00239 
00240 /* internal state, no threaded opengl! XXX */
00241 static wmWindow *_curwindow= NULL;
00242 static wmSubWindow *_curswin= NULL;
00243 
00244 void wmSubWindowScissorSet(wmWindow *win, int swinid, rcti *srct)
00245 {
00246     int width, height;
00247     _curswin= swin_from_swinid(win, swinid);
00248     
00249     if(_curswin==NULL) {
00250         printf("wmSubWindowSet %d: doesn't exist\n", swinid);
00251         return;
00252     }
00253     
00254     win->curswin= _curswin;
00255     _curwindow= win;
00256     
00257     width= _curswin->winrct.xmax - _curswin->winrct.xmin + 1;
00258     height= _curswin->winrct.ymax - _curswin->winrct.ymin + 1;
00259     glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
00260 
00261     if(srct) {
00262         width= srct->xmax - srct->xmin + 1;
00263         height= srct->ymax - srct->ymin + 1;
00264         glScissor(srct->xmin, srct->ymin, width, height);
00265     }
00266     else
00267         glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
00268     
00269     wmOrtho2(-0.375f, (float)width-0.375f, -0.375f, (float)height-0.375f);
00270     glLoadIdentity();
00271 
00272     glFlush();
00273 }
00274 
00275 
00276 /* enable the WM versions of opengl calls */
00277 void wmSubWindowSet(wmWindow *win, int swinid)
00278 {
00279     wmSubWindowScissorSet(win, swinid, NULL);
00280 }
00281 
00282 void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
00283 {
00284     glMatrixMode(GL_PROJECTION);
00285     glLoadIdentity();
00286     glFrustum(x1, x2, y1, y2, n, f);
00287     glMatrixMode(GL_MODELVIEW);
00288 }
00289 
00290 void wmOrtho(float x1, float x2, float y1, float y2, float n, float f)
00291 {
00292     glMatrixMode(GL_PROJECTION);
00293     glLoadIdentity();
00294 
00295     glOrtho(x1, x2, y1, y2, n, f);
00296 
00297     glMatrixMode(GL_MODELVIEW);
00298 }
00299 
00300 void wmOrtho2(float x1, float x2, float y1, float y2)
00301 {
00302     /* prevent opengl from generating errors */
00303     if(x1==x2) x2+=1.0f;
00304     if(y1==y2) y2+=1.0f;
00305 
00306     wmOrtho(x1, x2, y1, y2, -100, 100);
00307 }
00308 
00309 /* *************************** Framebuffer color depth, for selection codes ********************** */
00310 
00311 #ifdef __APPLE__
00312 
00313 /* apple seems to round colors to below and up on some configs */
00314 
00315 unsigned int index_to_framebuffer(int index)
00316 {
00317     unsigned int i= index;
00318 
00319     switch(GPU_color_depth()) {
00320     case 12:
00321         i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
00322         /* sometimes dithering subtracts! */
00323         i |= 0x070707;
00324         break;
00325     case 15:
00326     case 16:
00327         i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
00328         i |= 0x030303;
00329         break;
00330     case 24:
00331         break;
00332     default:    // 18 bits... 
00333         i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
00334         i |= 0x010101;
00335         break;
00336     }
00337     
00338     return i;
00339 }
00340 
00341 #else
00342 
00343 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
00344 
00345 unsigned int index_to_framebuffer(int index)
00346 {
00347     unsigned int i= index;
00348     
00349     switch(GPU_color_depth()) {
00350         case 8:
00351             i= ((i & 48)<<18) + ((i & 12)<<12) + ((i & 3)<<6);
00352             i |= 0x3F3F3F;
00353             break;
00354         case 12:
00355             i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
00356             /* sometimes dithering subtracts! */
00357             i |= 0x0F0F0F;
00358             break;
00359         case 15:
00360         case 16:
00361             i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
00362             i |= 0x070707;
00363             break;
00364         case 24:
00365             break;
00366         default:    // 18 bits... 
00367             i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
00368             i |= 0x030303;
00369             break;
00370     }
00371     
00372     return i;
00373 }
00374 
00375 #endif
00376 
00377 void WM_set_framebuffer_index_color(int index)
00378 {
00379     const int col= index_to_framebuffer(index);
00380     cpack(col);
00381 }
00382 
00383 int WM_framebuffer_to_index(unsigned int col)
00384 {
00385     if (col==0) return 0;
00386 
00387     switch(GPU_color_depth()) {
00388     case 8:
00389         return ((col & 0xC00000)>>18) + ((col & 0xC000)>>12) + ((col & 0xC0)>>6);
00390     case 12:
00391         return ((col & 0xF00000)>>12) + ((col & 0xF000)>>8) + ((col & 0xF0)>>4);
00392     case 15:
00393     case 16:
00394         return ((col & 0xF80000)>>9) + ((col & 0xF800)>>6) + ((col & 0xF8)>>3);
00395     case 24:
00396         return col & 0xFFFFFF;
00397     default: // 18 bits...
00398         return ((col & 0xFC0000)>>6) + ((col & 0xFC00)>>4) + ((col & 0xFC)>>2);
00399     }       
00400 }
00401 
00402 
00403 /* ********** END MY WINDOW ************** */
00404