Change the core internal event dispatch to use a BWinEvent structure
[blender.git] / source / blender / src / mywindow.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * vervanging voor een aantal fie's zoals swinopen, winset,  (zie onder)
32  * dit alles omdat GL en X te traag zijn
33  * feb: Opengl en toch maar naar X!
34  */
35
36 #include <string.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifdef WIN32
43 #include "BLI_winstuff.h"
44 #endif
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_arithb.h"
49 #include "BLI_editVert.h"
50 #include "BLI_gsqueue.h"
51
52 #include "DNA_screen_types.h"
53
54 #include "BKE_global.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58 #include "BIF_mywindow.h"
59 #include "BIF_screen.h"
60
61 #include "mydevice.h"
62 #include "blendef.h"
63
64 #include "winlay.h"
65
66 typedef struct {
67         struct bWindow *next, *prev;
68         int id, pad;
69         
70         int xmin, xmax, ymin, ymax;
71         float viewmat[4][4], winmat[4][4];
72
73         GSQueue *qevents;
74 } bWindow;
75
76 /* globals */
77 static Window *winlay_mainwindow;
78 static int curswin=0;
79 static bWindow *swinarray[MAXWIN]= {0};
80 static bWindow mainwindow, renderwindow;
81 static int mainwin_color_depth;
82
83 void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey)
84 {
85         int r, g, b;
86         
87         winlay_mainwindow= win;
88         
89         swinarray[1]= &mainwindow;
90         curswin= 1;
91
92         mainwindow.xmin= orx;
93         mainwindow.ymin= ory;
94         mainwindow.xmax= orx+sizex-1;
95         mainwindow.ymax= ory+sizey-1;
96         mainwindow.qevents= NULL;
97
98         myortho2(-0.5, (float)sizex-0.5, -0.5, (float)sizey-0.5);
99         glLoadIdentity();
100                 
101         glGetFloatv(GL_PROJECTION_MATRIX, (float *)mainwindow.winmat);
102         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)mainwindow.viewmat);
103         
104         glGetIntegerv(GL_RED_BITS, &r);
105         glGetIntegerv(GL_GREEN_BITS, &g);
106         glGetIntegerv(GL_BLUE_BITS, &b);
107
108         mainwin_color_depth= r + g + b;
109 }
110
111 /* XXXXXXXXXXXXXXXX very hacky, not allowed to release
112  * again after 2.24
113  *
114  * Nah ha! And you thought you'd be in business that long!
115  */
116 void mywindow_build_and_set_renderwin(void)
117 {
118         glGetFloatv(GL_PROJECTION_MATRIX, (float *)renderwindow.winmat);
119         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)renderwindow.viewmat);
120         
121         swinarray[2]= &renderwindow;
122         renderwindow.qevents= NULL;
123
124         curswin= 2;
125 }
126
127 /* ------------------------------------------------------------------------- */
128
129         /* XXXXX, remove later */
130 static bWindow *bwin_from_winid(int winid)
131 {
132         bWindow *bwin= swinarray[winid];
133         if (!bwin) {
134                 printf("bwin_from_winid: Internal error, bad winid: %d\n", winid);
135         }
136         return bwin;
137 }
138
139 int bwin_qtest(int winid)
140 {
141         return !BLI_gsqueue_is_empty(bwin_from_winid(winid)->qevents);
142 }
143 int bwin_qread(int winid, BWinEvent *evt_r)
144 {
145         if (bwin_qtest(winid)) {
146                 BLI_gsqueue_pop(bwin_from_winid(winid)->qevents, evt_r);
147                 return 1;
148         } else {
149                 return 0;
150         }
151 }
152 void bwin_qadd(int winid, BWinEvent *evt)
153 {
154         BLI_gsqueue_push(bwin_from_winid(winid)->qevents, evt);
155 }
156
157 /* ------------------------------------------------------------------------- */
158
159 void bwin_get_rect(int winid, rcti *rect_r)
160 {
161         bWindow *win= bwin_from_winid(winid);
162
163         rect_r->xmin= win->xmin;
164         rect_r->ymin= win->ymin;
165         rect_r->xmax= win->xmax;
166         rect_r->ymax= win->ymax;
167 }
168
169 void bwin_getsize(int win, int *x, int *y) 
170 {
171         if(win<4) {
172                 if (win==1) {
173                         window_get_size(winlay_mainwindow, x, y);
174                 } else {
175                         printf("bwin_getsize: Internal error, bad winid: %d\n", win);
176                         *x= *y= 0;
177                 }
178         } else {
179                 bWindow *bwin= swinarray[win];
180                 if (bwin) {
181                         *x= bwin->xmax-bwin->xmin+1;
182                         *y= bwin->ymax-bwin->ymin+1;
183                 }
184         }
185 }
186
187 void bwin_getsuborigin(int win, int *x, int *y)
188 {
189         if(win<4) {
190                 *x= *y= 0;      
191         } else {
192                 bWindow *bwin= swinarray[win];
193                 if (bwin) {
194                         *x= bwin->xmin;
195                         *y= bwin->ymin;
196                 }
197         }
198 }
199
200 void bwin_getsinglematrix(int winid, float mat[][4])
201 {
202         bWindow *win;
203         float matview[4][4], matproj[4][4];
204
205         win= swinarray[winid];
206         if(win==0) {
207                 glGetFloatv(GL_PROJECTION_MATRIX, (float *)matproj);
208                 glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matview);
209                 Mat4MulMat4(mat, matview, matproj);
210         }
211         else {
212                 Mat4MulMat4(mat, win->viewmat, win->winmat);
213         }
214 }
215
216 /* ------------------------------------------------------------------------- */
217
218 void bwin_load_viewmatrix(int winid, float mat[][4])
219 {
220         bWindow *win= bwin_from_winid(winid);
221         
222         glLoadMatrixf(mat);
223         Mat4CpyMat4(win->viewmat, mat);
224 }
225 void bwin_load_winmatrix(int winid, float mat[][4])
226 {
227         bWindow *win= bwin_from_winid(winid);
228
229         glLoadMatrixf(mat);
230         Mat4CpyMat4(win->winmat, mat);
231 }
232
233 void bwin_get_viewmatrix(int winid, float mat[][4])
234 {
235         bWindow *win= bwin_from_winid(winid);
236         Mat4CpyMat4(mat, win->viewmat);
237 }
238 void bwin_get_winmatrix(int winid, float mat[][4])
239 {
240         bWindow *win= bwin_from_winid(winid);
241         Mat4CpyMat4(mat, win->winmat);
242 }
243
244 void bwin_multmatrix(int winid, float mat[][4])
245 {
246         bWindow *win= bwin_from_winid(winid);
247
248         glMultMatrixf((float*) mat);
249         glGetFloatv(GL_MODELVIEW_MATRIX, (float *)win->viewmat);
250 }
251
252 void bwin_clear_viewmat(int swin)
253 {
254         bWindow *win;
255
256         win= swinarray[swin];
257         if(win==0) return;
258
259         memset(win->viewmat, 0, sizeof(win->viewmat));
260         win->viewmat[0][0]= 1.0;
261         win->viewmat[1][1]= 1.0;
262         win->viewmat[2][2]= 1.0;
263         win->viewmat[3][3]= 1.0;
264 }
265
266
267 void myloadmatrix(float mat[][4])
268 {
269         if (glaGetOneInteger(GL_MATRIX_MODE)==GL_MODELVIEW) {
270                 bwin_load_viewmatrix(curswin, mat);
271         } else {
272                 bwin_load_winmatrix(curswin, mat);
273         }
274 }
275
276 void mygetmatrix(float mat[][4])
277 {
278         if (glaGetOneInteger(GL_MATRIX_MODE)==GL_MODELVIEW) {
279                 bwin_get_viewmatrix(curswin, mat);
280         } else {
281                 bwin_get_winmatrix(curswin, mat);
282         }
283 }
284
285 void mymultmatrix(float mat[][4])
286 {
287         bwin_multmatrix(curswin, mat);
288 }
289
290 void mygetsingmatrix(float mat[][4])
291 {
292         bwin_getsinglematrix(curswin, mat);
293 }
294
295 int mywinget(void)
296 {
297         return curswin;
298 }
299
300 void mywinset(int wid)
301 {
302         bWindow *win;
303
304         win= swinarray[wid];
305         if(win==0) {
306                 printf("mywinset %d: doesn't exist\n", wid);
307                 return;
308         }
309
310         if (wid == 1) { /* main window */
311                 glViewport(0,  0, ( win->xmax-win->xmin)+1, ( win->ymax-win->ymin)+1);
312                 glScissor(0,  0, ( win->xmax-win->xmin)+1, ( win->ymax-win->ymin)+1);
313         }
314         else {
315                 int width= (win->xmax - win->xmin)+1;
316                 int height= (win->ymax - win->ymin)+1;
317
318                         /* CRITICAL, this clamping ensures that
319                          * the viewport never goes outside the screen
320                          * edges (assuming the x, y coords aren't
321                          * outside). This causes a hardware lock
322                          * on Matrox cards if it happens.
323                          * 
324                          * Really Blender should never _ever_ try
325                          * to do such a thing, but just to be safe
326                          * clamp it anyway (or fix the bScreen
327                          * scaling routine, and be damn sure you
328                          * fixed it). - zr
329                          */
330                 if (win->xmin + width>G.curscreen->sizex)
331                         width= G.curscreen->sizex - win->xmin;
332                 if (win->ymin + height>G.curscreen->sizey)
333                         height= G.curscreen->sizey - win->ymin;
334                 
335                 glViewport(win->xmin, win->ymin, width, height);
336                 glScissor(win->xmin, win->ymin, width, height);
337         }
338         
339         glMatrixMode(GL_PROJECTION);
340         glLoadMatrixf(&win->winmat[0][0]);
341         glMatrixMode(GL_MODELVIEW);
342         glLoadMatrixf(&win->viewmat[0][0]);
343
344         glFinish();
345         
346         curswin= wid;
347 }
348
349 int myswinopen(int parentid, int xmin, int xmax, int ymin, int ymax)
350 {
351         bWindow *win= NULL;
352         int freewinid;
353         
354         for (freewinid= 4; freewinid<MAXWIN; freewinid++)
355                 if (!swinarray[freewinid])
356                         break;
357         
358         if (freewinid==MAXWIN) {
359                 printf("too many windows\n");
360
361                 return 0;
362         } else {
363                 win= MEM_callocN(sizeof(*win), "winopen");
364
365                 win->id= freewinid;
366                 swinarray[win->id]= win;
367
368                 win->xmin= xmin;
369                 win->ymin= ymin;
370                 win->xmax= xmax;
371                 win->ymax= ymax;
372         
373                 win->qevents= BLI_gsqueue_new(sizeof(BWinEvent));
374
375                 Mat4One(win->viewmat);
376                 Mat4One(win->winmat);
377         
378                 mywinset(win->id);
379
380                 return win->id;
381         }
382 }
383
384 void mywinclose(int winid)
385 {
386         if (winid<4) {
387                 if (winid==1) {
388                         window_destroy(winlay_mainwindow);
389                         winlay_mainwindow= NULL;
390                 } else {
391                         printf("mwinclose: Internal error, bad winid: %d\n", winid);
392                 }
393         } else {
394                 bWindow *win= swinarray[winid];
395
396                 if (win) {
397                         BLI_gsqueue_free(win->qevents);
398                         MEM_freeN(win);
399                 } else {
400                         printf("mwinclose: Internal error, bad winid: %d\n", winid);
401                 }
402         }
403
404         swinarray[winid]= 0;
405         if (curswin==winid) curswin= 0;
406 }
407
408 void mywinposition(int winid, int xmin, int xmax, int ymin, int ymax) /* let op: andere syntax */
409 {
410         bWindow *win= bwin_from_winid(winid);
411         
412         win->xmin= xmin;
413         win->ymin= ymin;
414         win->xmax= xmax;
415         win->ymax= ymax;
416 }
417
418
419 void bwin_ortho(int winid, float x1, float x2, float y1, float y2, float n, float f)
420 {
421         bWindow *bwin= bwin_from_winid(winid);
422         
423         glMatrixMode(GL_PROJECTION);
424         glLoadIdentity();
425         glOrtho(x1, x2, y1, y2, n, f);
426
427         glGetFloatv(GL_PROJECTION_MATRIX, (float *)bwin->winmat);
428         glMatrixMode(GL_MODELVIEW);
429 }
430
431 void bwin_ortho2(int win, float x1, float x2, float y1, float y2)
432 {
433         bwin_ortho(win, x1, x2, y1, y2, -1, 1);
434 }
435
436 void bwin_frustum(int winid, float x1, float x2, float y1, float y2, float n, float f)
437 {
438         bWindow *win= bwin_from_winid(winid);
439
440         glMatrixMode(GL_PROJECTION);
441         glLoadIdentity();
442         glFrustum(x1, x2, y1, y2, n, f);
443
444         glGetFloatv(GL_PROJECTION_MATRIX, (float *)win->winmat);
445         glMatrixMode(GL_MODELVIEW);
446 }
447
448 void myortho(float x1, float x2, float y1, float y2, float n, float f)
449 {
450         bwin_ortho(curswin, x1, x2, y1, y2, n, f);
451 }
452
453 void myortho2(float x1, float x2, float y1, float y2)
454 {
455         bwin_ortho(curswin, x1, x2, y1, y2, -1, 1);
456 }
457
458 void mywindow(float x1, float x2, float y1, float y2, float n, float f)
459 {
460         bwin_frustum(curswin, x1, x2, y1, y2, n, f);
461 }
462
463 unsigned int index_to_framebuffer(int index)
464 {
465         unsigned int i= index;
466
467         switch(mainwin_color_depth) {
468         case 8:
469                 i= ((i & 48)<<18) + ((i & 12)<<12) + ((i & 3)<<6);
470                 i |= 0x3F3F3F;
471                 break;
472         case 12:
473                 i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
474                 /* sometimes dithering subtracts! */
475                 i |= 0x0F0F0F;
476                 break;
477         case 15:
478         case 16:
479                 i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
480                 i |= 0x070707;
481                 break;
482         default:
483                 i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
484                 i |= 0x030303;
485                 break;
486         }
487         
488         return i;
489 }
490
491 int framebuffer_to_index(unsigned int col)
492 {
493         if (col==0) return 0;
494
495         switch(mainwin_color_depth) {
496         case 8:
497                 return ((col & 0xC00000)>>18) + ((col & 0xC000)>>12) + ((col & 0xC0)>>6);
498         case 12:
499                 return ((col & 0xF00000)>>12) + ((col & 0xF000)>>8) + ((col & 0xF0)>>4);
500         case 15:
501         case 16:
502                 return ((col & 0xF80000)>>9) + ((col & 0xF800)>>6) + ((col & 0xF8)>>3);
503         default:
504                 return ((col & 0xFC0000)>>6) + ((col & 0xFC00)>>4) + ((col & 0xFC)>>2);
505         }               
506 }
507
508
509 /* ********** END MY WINDOW ************** */
510
511 #ifdef WIN32
512 static int is_a_really_crappy_nvidia_card(void) {
513         static int well_is_it= -1;
514
515                 /* Do you understand the implication? Do you? */
516         if (well_is_it==-1)
517                 well_is_it= (strcmp((char*) glGetString(GL_VENDOR), "NVIDIA Corporation") == 0);
518
519         return well_is_it;
520 }
521 #endif
522
523 void myswapbuffers(void)
524 {
525         ScrArea *sa;
526         
527         sa= G.curscreen->areabase.first;
528         while(sa) {
529                 if(sa->win_swap==WIN_BACK_OK) sa->win_swap= WIN_FRONT_OK;
530                 if(sa->head_swap==WIN_BACK_OK) sa->head_swap= WIN_FRONT_OK;
531                 
532                 sa= sa->next;
533         }
534
535         /* HACK, some windows drivers feel they should honor the scissor
536          * test when swapping buffers, disable the test while swapping
537          * on WIN32. (namely Matrox and NVidia's new drivers around Oct 1 2001)
538          * - zr
539          */
540
541 #ifdef WIN32
542                 /* HACK, in some NVidia driver release some kind of
543                  * fancy optimiziation (I presume) was put in which for
544                  * some reason causes parts of the buffer not to be
545                  * swapped. One way to defeat it is the following wierd
546                  * code (which we only do for nvidia cards). This should
547                  * be removed if NVidia fixes their drivers. - zr
548                  */
549         if (is_a_really_crappy_nvidia_card()) {
550                 glDrawBuffer(GL_FRONT);
551
552                 glBegin(GL_LINES);
553                 glEnd();
554
555                 glDrawBuffer(GL_BACK);
556         }
557
558         glDisable(GL_SCISSOR_TEST);
559         window_swap_buffers(winlay_mainwindow);
560         glEnable(GL_SCISSOR_TEST);
561 #else
562         window_swap_buffers(winlay_mainwindow);
563 #endif
564 }
565
566
567 /* *********************** PATTERNS ENZO ***************** */
568
569 void setlinestyle(int nr)
570 {
571         if(nr==0) {
572                 glDisable(GL_LINE_STIPPLE);
573         }
574         else {
575                 
576                 glEnable(GL_LINE_STIPPLE);
577                 glLineStipple(nr, 0xAAAA);
578         }
579 }
580
581 /*******************/
582 /*******************/
583 /*  Menu utilities */
584
585 static int *frontbuffer_save= NULL;
586 static int ov_x, ov_y, ov_sx, ov_sy;
587
588 void my_put_frontbuffer_image(void)
589 {
590         if (frontbuffer_save) {
591                 glRasterPos2f( (float)ov_x -0.5,  (float)ov_y - 0.5 );
592                 glDrawPixels(ov_sx, ov_sy, GL_RGBA, GL_UNSIGNED_BYTE, frontbuffer_save);
593                 MEM_freeN(frontbuffer_save);
594                 frontbuffer_save= NULL;
595         }
596 }
597
598 void my_get_frontbuffer_image(int x, int y, int sx, int sy)
599 {
600         if(frontbuffer_save) return;
601
602         ov_x= x;
603         ov_y= y;
604         ov_sx= sx;
605         ov_sy= sy;
606         
607         if(sx>1 && sy>1) {
608                 frontbuffer_save= MEM_mallocN(sx*sy*4, "temp_frontbuffer_image");
609                 glReadPixels(x, y, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, frontbuffer_save);
610         }
611
612         #ifdef WIN32
613         /* ander coordinatensysteem! */
614         y= (G.curscreen->sizey-y);
615         
616         if(curswin>3) {
617                 y -= curarea->winrct.ymin;
618         }
619         #endif
620 }
621
622 int mywin_inmenu(void) {
623         return frontbuffer_save?1:0;
624 }
625
626 void mywin_getmenu_rect(int *x, int *y, int *sx, int *sy) {
627         *x= ov_x;
628         *sx= ov_sx;
629         *sy= ov_sy;
630
631 #if defined(WIN32) || defined (__BeOS)
632         *y= ov_y;
633 #else
634         *y= (G.curscreen->sizey - ov_y) - ov_sy;
635 #endif  
636 }