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