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