doxygen: prevent GPL license block from being parsed as doxygen comment.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #include "BLI_utildefines.h"
43
44
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47
48 #include "BIF_gl.h"
49
50 #include "GPU_extensions.h"
51
52 #include "WM_api.h"
53 #include "wm_subwindow.h"
54 #include "wm_window.h"
55
56 /* wmSubWindow stored in wmWindow... but not exposed outside this C file */
57 /* it seems a bit redundant (area regions can store it too, but we keep it
58    because we can store all kind of future opengl fanciness here */
59
60 /* we use indices and array because:
61    - index has safety, no pointers from this C file hanging around
62    - fast lookups of indices with array, list would give overhead
63    - old code used it this way...
64    - keep option open to have 2 screens using same window
65 */
66
67 typedef struct wmSubWindow {
68         struct wmSubWindow *next, *prev;
69         
70         rcti winrct;
71         int swinid;
72 } wmSubWindow;
73
74
75 /* ******************* open, free, set, get data ******************** */
76
77 /* not subwindow itself */
78 static void wm_subwindow_free(wmSubWindow *UNUSED(swin))
79 {
80         /* future fancy stuff */
81 }
82
83 void wm_subwindows_free(wmWindow *win)
84 {
85         wmSubWindow *swin;
86         
87         for(swin= win->subwindows.first; swin; swin= swin->next)
88                 wm_subwindow_free(swin);
89         
90         BLI_freelistN(&win->subwindows);
91 }
92
93
94 int wm_subwindow_get(wmWindow *win)     
95 {
96         if(win->curswin)
97                 return win->curswin->swinid;
98         return 0;
99 }
100
101 static wmSubWindow *swin_from_swinid(wmWindow *win, int swinid)
102 {
103         wmSubWindow *swin;
104         
105         for(swin= win->subwindows.first; swin; swin= swin->next)
106                 if(swin->swinid==swinid)
107                         break;
108         return swin;
109 }
110
111 void wm_subwindow_getsize(wmWindow *win, int swinid, int *x, int *y) 
112 {
113         wmSubWindow *swin= swin_from_swinid(win, swinid);
114
115         if(swin) {
116                 *x= swin->winrct.xmax - swin->winrct.xmin + 1;
117                 *y= swin->winrct.ymax - swin->winrct.ymin + 1;
118         }
119 }
120
121 void wm_subwindow_getorigin(wmWindow *win, int swinid, int *x, int *y)
122 {
123         wmSubWindow *swin= swin_from_swinid(win, swinid);
124
125         if(swin) {
126                 *x= swin->winrct.xmin;
127                 *y= swin->winrct.ymin;
128         }
129 }
130
131 void wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[][4])
132 {
133         wmSubWindow *swin= swin_from_swinid(win, swinid);
134
135         if(swin) {
136                 /* used by UI, should find a better way to get the matrix there */
137                 if(swinid == win->screen->mainwin) {
138                         int width, height;
139
140                         wm_subwindow_getsize(win, swin->swinid, &width, &height);
141                         orthographic_m4(mat, -0.375, (float)width-0.375, -0.375, (float)height-0.375, -100, 100);
142                 }
143                 else
144                         glGetFloatv(GL_PROJECTION_MATRIX, (float*)mat);
145         }
146 }
147
148 /* always sets pixel-precise 2D window/view matrices */
149 /* coords is in whole pixels. xmin = 15, xmax= 16: means window is 2 pix big */
150 int wm_subwindow_open(wmWindow *win, rcti *winrct)
151 {
152         wmSubWindow *swin;
153         int width, height;
154         int freewinid= 1;
155         
156         for(swin= win->subwindows.first; swin; swin= swin->next)
157                 if(freewinid <= swin->swinid)
158                         freewinid= swin->swinid+1;
159
160         win->curswin= swin= MEM_callocN(sizeof(wmSubWindow), "swinopen");
161         BLI_addtail(&win->subwindows, swin);
162         
163         if(G.f & G_DEBUG) printf("swin %d added\n", freewinid);
164         swin->swinid= freewinid;
165         swin->winrct= *winrct;
166
167         /* and we appy it all right away */
168         wmSubWindowSet(win, swin->swinid);
169         
170         /* extra service */
171         wm_subwindow_getsize(win, swin->swinid, &width, &height);
172         wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
173         glLoadIdentity();
174
175         return swin->swinid;
176 }
177
178
179 void wm_subwindow_close(wmWindow *win, int swinid)
180 {
181         wmSubWindow *swin= swin_from_swinid(win, swinid);
182
183         if (swin) {
184                 if (swin==win->curswin)
185                         win->curswin= NULL;
186                 wm_subwindow_free(swin);
187                 BLI_remlink(&win->subwindows, swin);
188                 MEM_freeN(swin);
189         } 
190         else {
191                 printf("wm_subwindow_close: Internal error, bad winid: %d\n", swinid);
192         }
193
194 }
195
196 /* pixels go from 0-99 for a 100 pixel window */
197 void wm_subwindow_position(wmWindow *win, int swinid, rcti *winrct)
198 {
199         wmSubWindow *swin= swin_from_swinid(win, swinid);
200         
201         if(swin) {
202                 int width, height;
203                 
204                 swin->winrct= *winrct;
205                 
206                 /* CRITICAL, this clamping ensures that
207                         * the viewport never goes outside the screen
208                         * edges (assuming the x, y coords aren't
209                                          * outside). This caused a hardware lock
210                         * on Matrox cards if it happens.
211                         * 
212                         * Really Blender should never _ever_ try
213                         * to do such a thing, but just to be safe
214                         * clamp it anyway (or fix the bScreen
215                         * scaling routine, and be damn sure you
216                         * fixed it). - zr  (2001!)
217                         */
218                 
219                 if (swin->winrct.xmax > win->sizex)
220                         swin->winrct.xmax= win->sizex;
221                 if (swin->winrct.ymax > win->sizey)
222                         swin->winrct.ymax= win->sizey;
223                 
224                 /* extra service */
225                 wmSubWindowSet(win, swinid);
226                 wm_subwindow_getsize(win, swinid, &width, &height);
227                 wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
228         }
229         else {
230                 printf("wm_subwindow_position: Internal error, bad winid: %d\n", swinid);
231         }
232 }
233
234 /* ---------------- WM versions of OpenGL calls, using glBlah() syntax ------------------------ */
235 /* ----------------- exported in WM_api.h ------------------------------------------------------ */
236
237 /* internal state, no threaded opengl! XXX */
238 static wmWindow *_curwindow= NULL;
239 static wmSubWindow *_curswin= NULL;
240
241 void wmSubWindowScissorSet(wmWindow *win, int swinid, rcti *srct)
242 {
243         int width, height;
244         _curswin= swin_from_swinid(win, swinid);
245         
246         if(_curswin==NULL) {
247                 printf("wmSubWindowSet %d: doesn't exist\n", swinid);
248                 return;
249         }
250         
251         win->curswin= _curswin;
252         _curwindow= win;
253         
254         width= _curswin->winrct.xmax - _curswin->winrct.xmin + 1;
255         height= _curswin->winrct.ymax - _curswin->winrct.ymin + 1;
256         glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
257
258         if(srct) {
259                 width= srct->xmax - srct->xmin + 1;
260                 height= srct->ymax - srct->ymin + 1;
261                 glScissor(srct->xmin, srct->ymin, width, height);
262         }
263         else
264                 glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
265         
266         wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
267         glLoadIdentity();
268
269         glFlush();
270 }
271
272
273 /* enable the WM versions of opengl calls */
274 void wmSubWindowSet(wmWindow *win, int swinid)
275 {
276         wmSubWindowScissorSet(win, swinid, NULL);
277 }
278
279 void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
280 {
281         glMatrixMode(GL_PROJECTION);
282         glLoadIdentity();
283         glFrustum(x1, x2, y1, y2, n, f);
284         glMatrixMode(GL_MODELVIEW);
285 }
286
287 void wmOrtho(float x1, float x2, float y1, float y2, float n, float f)
288 {
289         glMatrixMode(GL_PROJECTION);
290         glLoadIdentity();
291
292         glOrtho(x1, x2, y1, y2, n, f);
293
294         glMatrixMode(GL_MODELVIEW);
295 }
296
297 void wmOrtho2(float x1, float x2, float y1, float y2)
298 {
299         /* prevent opengl from generating errors */
300         if(x1==x2) x2+=1.0;
301         if(y1==y2) y2+=1.0;
302
303         wmOrtho(x1, x2, y1, y2, -100, 100);
304 }
305
306 /* *************************** Framebuffer color depth, for selection codes ********************** */
307
308 #ifdef __APPLE__
309
310 /* apple seems to round colors to below and up on some configs */
311
312 unsigned int index_to_framebuffer(int index)
313 {
314         unsigned int i= index;
315
316         switch(GPU_color_depth()) {
317         case 12:
318                 i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
319                 /* sometimes dithering subtracts! */
320                 i |= 0x070707;
321                 break;
322         case 15:
323         case 16:
324                 i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
325                 i |= 0x030303;
326                 break;
327         case 24:
328                 break;
329         default:        // 18 bits... 
330                 i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
331                 i |= 0x010101;
332                 break;
333         }
334         
335         return i;
336 }
337
338 #else
339
340 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
341
342 unsigned int index_to_framebuffer(int index)
343 {
344         unsigned int i= index;
345         
346         switch(GPU_color_depth()) {
347                 case 8:
348                         i= ((i & 48)<<18) + ((i & 12)<<12) + ((i & 3)<<6);
349                         i |= 0x3F3F3F;
350                         break;
351                 case 12:
352                         i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
353                         /* sometimes dithering subtracts! */
354                         i |= 0x0F0F0F;
355                         break;
356                 case 15:
357                 case 16:
358                         i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
359                         i |= 0x070707;
360                         break;
361                 case 24:
362                         break;
363                 default:        // 18 bits... 
364                         i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
365                         i |= 0x030303;
366                         break;
367         }
368         
369         return i;
370 }
371
372 #endif
373
374 void WM_set_framebuffer_index_color(int index)
375 {
376         cpack(index_to_framebuffer(index));
377 }
378
379 int WM_framebuffer_to_index(unsigned int col)
380 {
381         if (col==0) return 0;
382
383         switch(GPU_color_depth()) {
384         case 8:
385                 return ((col & 0xC00000)>>18) + ((col & 0xC000)>>12) + ((col & 0xC0)>>6);
386         case 12:
387                 return ((col & 0xF00000)>>12) + ((col & 0xF000)>>8) + ((col & 0xF0)>>4);
388         case 15:
389         case 16:
390                 return ((col & 0xF80000)>>9) + ((col & 0xF800)>>6) + ((col & 0xF8)>>3);
391         case 24:
392                 return col & 0xFFFFFF;
393         default: // 18 bits...
394                 return ((col & 0xFC0000)>>6) + ((col & 0xFC00)>>4) + ((col & 0xFC)>>2);
395         }               
396 }
397
398
399 /* ********** END MY WINDOW ************** */
400