Fix for problem drawing second level popup menus due to recent commit,
[blender.git] / source / blender / windowmanager / intern / wm_subwindow.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): 2007 Blender Foundation (refactor)
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  *
28  * Subwindow opengl handling. 
29  * BTW: subwindows open/close in X11 are way too slow, tried it, and choose for my own system... (ton)
30  * 
31  */
32
33 #include <string.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_windowmanager_types.h"
38 #include "DNA_screen_types.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_math.h"
42
43 #include "BKE_context.h"
44 #include "BKE_global.h"
45
46 #include "BIF_gl.h"
47 #include "BIF_glutil.h"
48
49 #include "WM_api.h"
50 #include "wm_subwindow.h"
51 #include "wm_window.h"
52
53 /* wmSubWindow stored in wmWindow... but not exposed outside this C file */
54 /* it seems a bit redundant (area regions can store it too, but we keep it
55    because we can store all kind of future opengl fanciness here */
56
57 /* we use indices and array because:
58    - index has safety, no pointers from this C file hanging around
59    - fast lookups of indices with array, list would give overhead
60    - old code used it this way...
61    - keep option open to have 2 screens using same window
62 */
63
64 typedef struct wmSubWindow {
65         struct wmSubWindow *next, *prev;
66         
67         rcti winrct;
68         int swinid;
69 } wmSubWindow;
70
71
72 /* ******************* open, free, set, get data ******************** */
73
74 /* not subwindow itself */
75 static void wm_subwindow_free(wmSubWindow *swin)
76 {
77         /* future fancy stuff */
78 }
79
80 void wm_subwindows_free(wmWindow *win)
81 {
82         wmSubWindow *swin;
83         
84         for(swin= win->subwindows.first; swin; swin= swin->next)
85                 wm_subwindow_free(swin);
86         
87         BLI_freelistN(&win->subwindows);
88 }
89
90
91 int wm_subwindow_get(wmWindow *win)     
92 {
93         if(win->curswin)
94                 return win->curswin->swinid;
95         return 0;
96 }
97
98 static wmSubWindow *swin_from_swinid(wmWindow *win, int swinid)
99 {
100         wmSubWindow *swin;
101         
102         for(swin= win->subwindows.first; swin; swin= swin->next)
103                 if(swin->swinid==swinid)
104                         break;
105         return swin;
106 }
107
108 void wm_subwindow_getsize(wmWindow *win, int swinid, int *x, int *y) 
109 {
110         wmSubWindow *swin= swin_from_swinid(win, swinid);
111
112         if(swin) {
113                 *x= swin->winrct.xmax - swin->winrct.xmin + 1;
114                 *y= swin->winrct.ymax - swin->winrct.ymin + 1;
115         }
116 }
117
118 void wm_subwindow_getorigin(wmWindow *win, int swinid, int *x, int *y)
119 {
120         wmSubWindow *swin= swin_from_swinid(win, swinid);
121
122         if(swin) {
123                 *x= swin->winrct.xmin;
124                 *y= swin->winrct.ymin;
125         }
126 }
127
128 void wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[][4])
129 {
130         wmSubWindow *swin= swin_from_swinid(win, swinid);
131
132         if(swin) {
133                 /* used by UI, should find a better way to get the matrix there */
134                 if(swinid == win->screen->mainwin) {
135                         int width, height;
136
137                         wm_subwindow_getsize(win, swin->swinid, &width, &height);
138                         orthographic_m4(mat, -0.375, (float)width-0.375, -0.375, (float)height-0.375, -100, 100);
139                 }
140                 else
141                         glGetFloatv(GL_PROJECTION_MATRIX, (float*)mat);
142         }
143 }
144
145 /* always sets pixel-precise 2D window/view matrices */
146 /* coords is in whole pixels. xmin = 15, xmax= 16: means window is 2 pix big */
147 int wm_subwindow_open(wmWindow *win, rcti *winrct)
148 {
149         wmSubWindow *swin;
150         int width, height;
151         int freewinid= 1;
152         
153         for(swin= win->subwindows.first; swin; swin= swin->next)
154                 if(freewinid <= swin->swinid)
155                         freewinid= swin->swinid+1;
156
157         win->curswin= swin= MEM_callocN(sizeof(wmSubWindow), "swinopen");
158         BLI_addtail(&win->subwindows, swin);
159         
160         if(G.f & G_DEBUG) printf("swin %d added\n", freewinid);
161         swin->swinid= freewinid;
162         swin->winrct= *winrct;
163
164         /* and we appy it all right away */
165         wmSubWindowSet(win, swin->swinid);
166         
167         /* extra service */
168         wm_subwindow_getsize(win, swin->swinid, &width, &height);
169         wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
170         glLoadIdentity();
171
172         return swin->swinid;
173 }
174
175
176 void wm_subwindow_close(wmWindow *win, int swinid)
177 {
178         wmSubWindow *swin= swin_from_swinid(win, swinid);
179
180         if (swin) {
181                 if (swin==win->curswin)
182                         win->curswin= NULL;
183                 wm_subwindow_free(swin);
184                 BLI_remlink(&win->subwindows, swin);
185                 MEM_freeN(swin);
186         } 
187         else {
188                 printf("wm_subwindow_close: Internal error, bad winid: %d\n", swinid);
189         }
190
191 }
192
193 /* pixels go from 0-99 for a 100 pixel window */
194 void wm_subwindow_position(wmWindow *win, int swinid, rcti *winrct)
195 {
196         wmSubWindow *swin= swin_from_swinid(win, swinid);
197         
198         if(swin) {
199                 int width, height;
200                 
201                 swin->winrct= *winrct;
202                 
203                 /* CRITICAL, this clamping ensures that
204                         * the viewport never goes outside the screen
205                         * edges (assuming the x, y coords aren't
206                                          * outside). This caused a hardware lock
207                         * on Matrox cards if it happens.
208                         * 
209                         * Really Blender should never _ever_ try
210                         * to do such a thing, but just to be safe
211                         * clamp it anyway (or fix the bScreen
212                     * scaling routine, and be damn sure you
213                     * fixed it). - zr  (2001!)
214                         */
215                 
216                 if (swin->winrct.xmax > win->sizex)
217                         swin->winrct.xmax= win->sizex;
218                 if (swin->winrct.ymax > win->sizey)
219                         swin->winrct.ymax= win->sizey;
220                 
221                 /* extra service */
222                 wmSubWindowSet(win, swinid);
223                 wm_subwindow_getsize(win, swinid, &width, &height);
224                 wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
225         }
226         else {
227                 printf("wm_subwindow_position: Internal error, bad winid: %d\n", swinid);
228         }
229 }
230
231 /* ---------------- WM versions of OpenGL calls, using glBlah() syntax ------------------------ */
232 /* ----------------- exported in WM_api.h ------------------------------------------------------ */
233
234 /* internal state, no threaded opengl! XXX */
235 static wmWindow *_curwindow= NULL;
236 static wmSubWindow *_curswin= NULL;
237
238 void wmSubWindowScissorSet(wmWindow *win, int swinid, rcti *srct)
239 {
240         int width, height;
241         _curswin= swin_from_swinid(win, swinid);
242         
243         if(_curswin==NULL) {
244                 printf("wmSubWindowSet %d: doesn't exist\n", swinid);
245                 return;
246         }
247         
248         win->curswin= _curswin;
249         _curwindow= win;
250         
251         width= _curswin->winrct.xmax - _curswin->winrct.xmin + 1;
252         height= _curswin->winrct.ymax - _curswin->winrct.ymin + 1;
253         glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
254
255         if(srct) {
256                 width= srct->xmax - srct->xmin + 1;
257                 height= srct->ymax - srct->ymin + 1;
258                 glScissor(srct->xmin, srct->ymin, width, height);
259         }
260         else
261                 glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
262         
263         wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
264         glLoadIdentity();
265
266         glFlush();
267 }
268
269
270 /* enable the WM versions of opengl calls */
271 void wmSubWindowSet(wmWindow *win, int swinid)
272 {
273         wmSubWindowScissorSet(win, swinid, NULL);
274 }
275
276 void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
277 {
278         glMatrixMode(GL_PROJECTION);
279         glLoadIdentity();
280         glFrustum(x1, x2, y1, y2, n, f);
281         glMatrixMode(GL_MODELVIEW);
282 }
283
284 void wmOrtho(float x1, float x2, float y1, float y2, float n, float f)
285 {
286         glMatrixMode(GL_PROJECTION);
287         glLoadIdentity();
288
289         glOrtho(x1, x2, y1, y2, n, f);
290
291         glMatrixMode(GL_MODELVIEW);
292 }
293
294 void wmOrtho2(float x1, float x2, float y1, float y2)
295 {
296         /* prevent opengl from generating errors */
297         if(x1==x2) x2+=1.0;
298         if(y1==y2) y2+=1.0;
299
300         wmOrtho(x1, x2, y1, y2, -100, 100);
301 }
302
303 /* *************************** Framebuffer color depth, for selection codes ********************** */
304
305 static int wm_get_colordepth(void)
306 {
307         static int mainwin_color_depth= 0;      
308         
309         if(mainwin_color_depth==0) {
310                 GLint r, g, b;
311                 
312                 glGetIntegerv(GL_RED_BITS, &r);
313                 glGetIntegerv(GL_GREEN_BITS, &g);
314                 glGetIntegerv(GL_BLUE_BITS, &b);
315                 
316                 mainwin_color_depth= r + g + b;
317                 if(G.f & G_DEBUG) {
318                         printf("Color depth r %d g %d b %d\n", (int)r, (int)g, (int)b);
319                         glGetIntegerv(GL_AUX_BUFFERS, &r);
320                         printf("Aux buffers: %d\n", (int)r);
321                 }
322         }
323         return mainwin_color_depth;
324 }
325
326
327 #ifdef __APPLE__
328
329 /* apple seems to round colors to below and up on some configs */
330
331 unsigned int index_to_framebuffer(int index)
332 {
333         unsigned int i= index;
334
335         switch(wm_get_colordepth()) {
336         case 12:
337                 i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
338                 /* sometimes dithering subtracts! */
339                 i |= 0x070707;
340                 break;
341         case 15:
342         case 16:
343                 i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
344                 i |= 0x030303;
345                 break;
346         case 24:
347                 break;
348         default:        // 18 bits... 
349                 i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
350                 i |= 0x010101;
351                 break;
352         }
353         
354         return i;
355 }
356
357 #else
358
359 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
360
361 unsigned int index_to_framebuffer(int index)
362 {
363         unsigned int i= index;
364         
365         switch(wm_get_colordepth()) {
366                 case 8:
367                         i= ((i & 48)<<18) + ((i & 12)<<12) + ((i & 3)<<6);
368                         i |= 0x3F3F3F;
369                         break;
370                 case 12:
371                         i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
372                         /* sometimes dithering subtracts! */
373                         i |= 0x0F0F0F;
374                         break;
375                 case 15:
376                 case 16:
377                         i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
378                         i |= 0x070707;
379                         break;
380                 case 24:
381                         break;
382                 default:        // 18 bits... 
383                         i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
384                         i |= 0x030303;
385                         break;
386         }
387         
388         return i;
389 }
390
391 #endif
392
393 void WM_set_framebuffer_index_color(int index)
394 {
395         cpack(index_to_framebuffer(index));
396 }
397
398 int WM_framebuffer_to_index(unsigned int col)
399 {
400         if (col==0) return 0;
401
402         switch(wm_get_colordepth()) {
403         case 8:
404                 return ((col & 0xC00000)>>18) + ((col & 0xC000)>>12) + ((col & 0xC0)>>6);
405         case 12:
406                 return ((col & 0xF00000)>>12) + ((col & 0xF000)>>8) + ((col & 0xF0)>>4);
407         case 15:
408         case 16:
409                 return ((col & 0xF80000)>>9) + ((col & 0xF800)>>6) + ((col & 0xF8)>>3);
410         case 24:
411                 return col & 0xFFFFFF;
412         default: // 18 bits...
413                 return ((col & 0xFC0000)>>6) + ((col & 0xFC00)>>4) + ((col & 0xFC)>>2);
414         }               
415 }
416
417
418 /* ********** END MY WINDOW ************** */
419