Code cleanup: warning fixes.
[blender.git] / source / blender / windowmanager / intern / wm_draw.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) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/windowmanager/intern/wm_draw.c
30  *  \ingroup wm
31  */
32
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <GL/glew.h>
37
38 #include "DNA_listBase.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_windowmanager_types.h"
41 #include "DNA_userdef_types.h"
42 #include "DNA_view3d_types.h"
43
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_context.h"
50 #include "BKE_global.h"
51
52
53 #include "GHOST_C-api.h"
54
55 #include "ED_screen.h"
56
57 #include "GPU_draw.h"
58 #include "GPU_extensions.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62 #include "wm.h"
63 #include "wm_draw.h"
64 #include "wm_window.h"
65 #include "wm_event_system.h"
66
67 /* swap */
68 #define WIN_NONE_OK             0
69 #define WIN_BACK_OK     1
70 #define WIN_FRONT_OK    2
71 #define WIN_BOTH_OK             3
72
73 /* ******************* drawing, overlays *************** */
74
75
76 static void wm_paintcursor_draw(bContext *C, ARegion *ar)
77 {
78         wmWindowManager *wm= CTX_wm_manager(C);
79         
80         if(wm->paintcursors.first) {
81                 wmWindow *win= CTX_wm_window(C);
82                 bScreen *screen= win->screen;
83                 wmPaintCursor *pc;
84
85                 if(screen->subwinactive == ar->swinid) {
86                         for(pc= wm->paintcursors.first; pc; pc= pc->next) {
87                                 if(pc->poll == NULL || pc->poll(C)) {
88                                         ARegion *ar_other= CTX_wm_region(C);
89                                         if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
90                                                 int x = 0, y = 0;
91                                                 wm_get_cursor_position(win, &x, &y);
92                                                 pc->draw(C, x - ar_other->winrct.xmin, y - ar_other->winrct.ymin, pc->customdata);
93                                         } else {
94                                                 pc->draw(C, win->eventstate->x - ar_other->winrct.xmin, win->eventstate->y - ar_other->winrct.ymin, pc->customdata);
95                                         }
96                                 }
97                         }
98                 }
99         }
100 }
101
102 /* ********************* drawing, swap ****************** */
103
104 static void wm_area_mark_invalid_backbuf(ScrArea *sa)
105 {
106         if(sa->spacetype == SPACE_VIEW3D)
107                 ((View3D*)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
108 }
109
110 static int wm_area_test_invalid_backbuf(ScrArea *sa)
111 {
112         if(sa->spacetype == SPACE_VIEW3D)
113                 return (((View3D*)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF);
114         else
115                 return 1;
116 }
117
118 /********************** draw all **************************/
119 /* - reference method, draw all each time                 */
120
121 static void wm_method_draw_full(bContext *C, wmWindow *win)
122 {
123         bScreen *screen= win->screen;
124         ScrArea *sa;
125         ARegion *ar;
126
127         /* draw area regions */
128         for(sa= screen->areabase.first; sa; sa= sa->next) {
129                 CTX_wm_area_set(C, sa);
130
131                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
132                         if(ar->swinid) {
133                                 CTX_wm_region_set(C, ar);
134                                 ED_region_do_draw(C, ar);
135                                 wm_paintcursor_draw(C, ar);
136                                 ED_area_overdraw_flush(sa, ar);
137                                 CTX_wm_region_set(C, NULL);
138                         }
139                 }
140                 
141                 wm_area_mark_invalid_backbuf(sa);
142                 CTX_wm_area_set(C, NULL);
143         }
144
145         ED_screen_draw(win);
146         ED_area_overdraw(C);
147
148         /* draw overlapping regions */
149         for(ar=screen->regionbase.first; ar; ar= ar->next) {
150                 if(ar->swinid) {
151                         CTX_wm_menu_set(C, ar);
152                         ED_region_do_draw(C, ar);
153                         CTX_wm_menu_set(C, NULL);
154                 }
155         }
156
157         if(screen->do_draw_gesture)
158                 wm_gesture_draw(win);
159 }
160
161 /****************** draw overlap all **********************/
162 /* - redraw marked areas, and anything that overlaps it   */
163 /* - it also handles swap exchange optionally, assuming   */
164 /*   that on swap no clearing happens and we get back the */
165 /*   same buffer as we swapped to the front               */
166
167 /* mark area-regions to redraw if overlapped with rect */
168 static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
169 {
170         ScrArea *sa;
171         ARegion *ar;
172
173         for(sa= screen->areabase.first; sa; sa= sa->next) {
174                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
175                         if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
176                                 ar->do_draw= RGN_DRAW;
177                                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
178                                 ar->swap= WIN_NONE_OK;
179                         }
180                 }
181         }
182 }
183
184 /* mark menu-regions to redraw if overlapped with rect */
185 static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
186 {
187         ARegion *ar;
188         
189         for(ar= screen->regionbase.first; ar; ar= ar->next) {
190                 if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
191                         ar->do_draw= RGN_DRAW;
192                         memset(&ar->drawrct, 0, sizeof(ar->drawrct));
193                         ar->swap= WIN_NONE_OK;
194                 }
195         }
196 }
197
198 static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
199 {
200         wmWindowManager *wm= CTX_wm_manager(C);
201         bScreen *screen= win->screen;
202         ScrArea *sa;
203         ARegion *ar;
204         static rcti rect= {0, 0, 0, 0};
205
206         /* after backbuffer selection draw, we need to redraw */
207         for(sa= screen->areabase.first; sa; sa= sa->next)
208                 for(ar= sa->regionbase.first; ar; ar= ar->next)
209                         if(ar->swinid && !wm_area_test_invalid_backbuf(sa))
210                                         ED_region_tag_redraw(ar);
211
212         /* flush overlapping regions */
213         if(screen->regionbase.first) {
214                 /* flush redraws of area regions up to overlapping regions */
215                 for(sa= screen->areabase.first; sa; sa= sa->next)
216                         for(ar= sa->regionbase.first; ar; ar= ar->next)
217                                 if(ar->swinid && ar->do_draw)
218                                         wm_flush_regions_up(screen, &ar->winrct);
219                 
220                 /* flush between overlapping regions */
221                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
222                         if(ar->swinid && ar->do_draw)
223                                 wm_flush_regions_up(screen, &ar->winrct);
224                 
225                 /* flush redraws of overlapping regions down to area regions */
226                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
227                         if(ar->swinid && ar->do_draw)
228                                 wm_flush_regions_down(screen, &ar->winrct);
229         }
230
231         /* flush drag item */
232         if(rect.xmin!=rect.xmax) {
233                 wm_flush_regions_down(screen, &rect);
234                 rect.xmin= rect.xmax = 0;
235         }
236         if(wm->drags.first) {
237                 /* doesnt draw, fills rect with boundbox */
238                 wm_drags_draw(C, win, &rect);
239         }
240         
241         /* draw marked area regions */
242         for(sa= screen->areabase.first; sa; sa= sa->next) {
243                 CTX_wm_area_set(C, sa);
244
245                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
246                         if(ar->swinid) {
247                                 if(ar->do_draw) {
248                                         CTX_wm_region_set(C, ar);
249                                         ED_region_do_draw(C, ar);
250                                         wm_paintcursor_draw(C, ar);
251                                         ED_area_overdraw_flush(sa, ar);
252                                         CTX_wm_region_set(C, NULL);
253
254                                         if(exchange)
255                                                 ar->swap= WIN_FRONT_OK;
256                                 }
257                                 else if(exchange) {
258                                         if(ar->swap == WIN_FRONT_OK) {
259                                                 CTX_wm_region_set(C, ar);
260                                                 ED_region_do_draw(C, ar);
261                                                 wm_paintcursor_draw(C, ar);
262                                                 ED_area_overdraw_flush(sa, ar);
263                                                 CTX_wm_region_set(C, NULL);
264
265                                                 ar->swap= WIN_BOTH_OK;
266                                         }
267                                         else if(ar->swap == WIN_BACK_OK)
268                                                 ar->swap= WIN_FRONT_OK;
269                                         else if(ar->swap == WIN_BOTH_OK)
270                                                 ar->swap= WIN_BOTH_OK;
271                                 }
272                         }
273                 }
274                 
275                 wm_area_mark_invalid_backbuf(sa);
276                 CTX_wm_area_set(C, NULL);
277         }
278
279         /* after area regions so we can do area 'overlay' drawing */
280         if(screen->do_draw) {
281                 ED_screen_draw(win);
282
283                 if(exchange)
284                         screen->swap= WIN_FRONT_OK;
285         }
286         else if(exchange) {
287                 if(screen->swap==WIN_FRONT_OK) {
288                         ED_screen_draw(win);
289                         screen->swap= WIN_BOTH_OK;
290                 }
291                 else if(screen->swap==WIN_BACK_OK)
292                         screen->swap= WIN_FRONT_OK;
293                 else if(screen->swap==WIN_BOTH_OK)
294                         screen->swap= WIN_BOTH_OK;
295         }
296
297         ED_area_overdraw(C);
298
299         /* draw marked overlapping regions */
300         for(ar=screen->regionbase.first; ar; ar= ar->next) {
301                 if(ar->swinid && ar->do_draw) {
302                         CTX_wm_menu_set(C, ar);
303                         ED_region_do_draw(C, ar);
304                         CTX_wm_menu_set(C, NULL);
305                 }
306         }
307
308         if(screen->do_draw_gesture)
309                 wm_gesture_draw(win);
310         
311         /* needs pixel coords in screen */
312         if(wm->drags.first) {
313                 wm_drags_draw(C, win, NULL);
314         }
315 }
316
317 #if 0
318 /******************** draw damage ************************/
319 /* - not implemented                                      */
320
321 static void wm_method_draw_damage(bContext *C, wmWindow *win)
322 {
323         wm_method_draw_all(C, win);
324 }
325 #endif
326
327 /****************** draw triple buffer ********************/
328 /* - area regions are written into a texture, without any */
329 /*   of the overlapping menus, brushes, gestures. these   */
330 /*   are redrawn each time.                               */
331 /*                                                        */
332 /* - if non-power of two textures are supported, that is  */
333 /*   used. if not, multiple smaller ones are used, with   */
334 /*   worst case wasted space being 23.4% for 3x3 textures */
335
336 #define MAX_N_TEX 3
337
338 typedef struct wmDrawTriple {
339         GLuint bind[MAX_N_TEX*MAX_N_TEX];
340         int x[MAX_N_TEX], y[MAX_N_TEX];
341         int nx, ny;
342         GLenum target;
343 } wmDrawTriple;
344
345 static int is_pow2(int n)
346 {
347         return ((n)&(n-1))==0;
348 }
349
350 static int smaller_pow2(int n)
351 {
352         while (!is_pow2(n))
353                 n= n&(n-1);
354
355         return n;
356 }
357
358 static int larger_pow2(int n)
359 {
360         if (is_pow2(n))
361                 return n;
362
363         while(!is_pow2(n))
364                 n= n&(n-1);
365
366         return n*2;
367 }
368
369 static void split_width(int x, int n, int *splitx, int *nx)
370 {
371         int a, newnx, waste;
372
373         /* if already power of two just use it */
374         if(is_pow2(x)) {
375                 splitx[0]= x;
376                 (*nx)++;
377                 return;
378         }
379
380         if(n == 1) {
381                 /* last part, we have to go larger */
382                 splitx[0]= larger_pow2(x);
383                 (*nx)++;
384         }
385         else {
386                 /* two or more parts to go, use smaller part */
387                 splitx[0]= smaller_pow2(x);
388                 newnx= ++(*nx);
389                 split_width(x-splitx[0], n-1, splitx+1, &newnx);
390
391                 for(waste=0, a=0; a<n; a++)
392                         waste += splitx[a];
393
394                 /* if we waste more space or use the same amount,
395                  * revert deeper splits and just use larger */
396                 if(waste >= larger_pow2(x)) {
397                         splitx[0]= larger_pow2(x);
398                         memset(splitx+1, 0, sizeof(int)*(n-1));
399                 }
400                 else
401                         *nx= newnx;
402         }
403 }
404
405 static void wm_draw_triple_free(wmWindow *win)
406 {
407         if(win->drawdata) {
408                 wmDrawTriple *triple= win->drawdata;
409
410                 glDeleteTextures(triple->nx*triple->ny, triple->bind);
411
412                 MEM_freeN(triple);
413
414                 win->drawdata= NULL;
415         }
416 }
417
418 static void wm_draw_triple_fail(bContext *C, wmWindow *win)
419 {
420         wm_draw_window_clear(win);
421
422         win->drawfail= 1;
423         wm_method_draw_overlap_all(C, win, 0);
424 }
425
426 static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
427 {
428         GLint maxsize;
429         int x, y;
430
431         /* compute texture sizes */
432         if(GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
433                 triple->target= GL_TEXTURE_RECTANGLE_ARB;
434                 triple->nx= 1;
435                 triple->ny= 1;
436                 triple->x[0]= win->sizex;
437                 triple->y[0]= win->sizey;
438         }
439         else if(GPU_non_power_of_two_support()) {
440                 triple->target= GL_TEXTURE_2D;
441                 triple->nx= 1;
442                 triple->ny= 1;
443                 triple->x[0]= win->sizex;
444                 triple->y[0]= win->sizey;
445         }
446         else {
447                 triple->target= GL_TEXTURE_2D;
448                 triple->nx= 0;
449                 triple->ny= 0;
450                 split_width(win->sizex, MAX_N_TEX, triple->x, &triple->nx);
451                 split_width(win->sizey, MAX_N_TEX, triple->y, &triple->ny);
452         }
453
454         /* generate texture names */
455         glGenTextures(triple->nx*triple->ny, triple->bind);
456
457         if(!triple->bind[0]) {
458                 /* not the typical failure case but we handle it anyway */
459                 printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
460                 return 0;
461         }
462
463         for(y=0; y<triple->ny; y++) {
464                 for(x=0; x<triple->nx; x++) {
465                         /* proxy texture is only guaranteed to test for the cases that
466                          * there is only one texture in use, which may not be the case */
467                         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
468
469                         if(triple->x[x] > maxsize || triple->y[y] > maxsize) {
470                                 glBindTexture(triple->target, 0);
471                                 printf("WM: failed to allocate texture for triple buffer drawing (texture too large for graphics card).\n");
472                                 return 0;
473                         }
474
475                         /* setup actual texture */
476                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
477                         glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
478                         glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
479                         glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
480                         // glColor still used with this enabled?
481                         // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE);
482                         glBindTexture(triple->target, 0);
483
484                         /* not sure if this works everywhere .. */
485                         if(glGetError() == GL_OUT_OF_MEMORY) {
486                                 printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
487                                 return 0;
488                         }
489                 }
490         }
491
492         return 1;
493 }
494
495 static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple)
496 {
497         float halfx, halfy, ratiox, ratioy;
498         int x, y, sizex, sizey, offx, offy;
499
500         glEnable(triple->target);
501
502         for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
503                 for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
504                         sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
505                         sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
506
507                         /* wmOrtho for the screen has this same offset */
508                         ratiox= sizex;
509                         ratioy= sizey;
510                         halfx= 0.375f;
511                         halfy= 0.375f;
512
513                         /* texture rectangle has unnormalized coordinates */
514                         if(triple->target == GL_TEXTURE_2D) {
515                                 ratiox /= triple->x[x];
516                                 ratioy /= triple->y[y];
517                                 halfx /= triple->x[x];
518                                 halfy /= triple->y[y];
519                         }
520
521                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
522
523                         glColor3f(1.0f, 1.0f, 1.0f);
524                         glBegin(GL_QUADS);
525                                 glTexCoord2f(halfx, halfy);
526                                 glVertex2f(offx, offy);
527
528                                 glTexCoord2f(ratiox+halfx, halfy);
529                                 glVertex2f(offx+sizex, offy);
530
531                                 glTexCoord2f(ratiox+halfx, ratioy+halfy);
532                                 glVertex2f(offx+sizex, offy+sizey);
533
534                                 glTexCoord2f(halfx, ratioy+halfy);
535                                 glVertex2f(offx, offy+sizey);
536                         glEnd();
537                 }
538         }
539
540         glBindTexture(triple->target, 0);
541         glDisable(triple->target);
542 }
543
544 static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
545 {
546         int x, y, sizex, sizey, offx, offy;
547
548         for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
549                 for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
550                         sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
551                         sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
552
553                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
554                         glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey);
555                 }
556         }
557
558         glBindTexture(triple->target, 0);
559 }
560
561 static void wm_method_draw_triple(bContext *C, wmWindow *win)
562 {
563         wmWindowManager *wm= CTX_wm_manager(C);
564         wmDrawTriple *triple;
565         bScreen *screen= win->screen;
566         ScrArea *sa;
567         ARegion *ar;
568         int copytex= 0, paintcursor= 1;
569
570         if(win->drawdata) {
571                 glClearColor(0, 0, 0, 0);
572                 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
573
574                 wmSubWindowSet(win, screen->mainwin);
575
576                 wm_triple_draw_textures(win, win->drawdata);
577         }
578         else {
579                 win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
580
581                 if(!wm_triple_gen_textures(win, win->drawdata))
582                 {
583                         wm_draw_triple_fail(C, win);
584                         return;
585                 }
586         }
587
588         triple= win->drawdata;
589
590         /* draw marked area regions */
591         for(sa= screen->areabase.first; sa; sa= sa->next) {
592                 CTX_wm_area_set(C, sa);
593
594                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
595                         if(ar->swinid && ar->do_draw) {
596                                 CTX_wm_region_set(C, ar);
597                                 ED_region_do_draw(C, ar);
598                                 ED_area_overdraw_flush(sa, ar);
599                                 CTX_wm_region_set(C, NULL);
600                                 copytex= 1;
601                         }
602                 }
603                 
604                 wm_area_mark_invalid_backbuf(sa);
605                 CTX_wm_area_set(C, NULL);
606         }
607
608         if(copytex) {
609                 wmSubWindowSet(win, screen->mainwin);
610                 ED_area_overdraw(C);
611
612                 wm_triple_copy_textures(win, triple);
613         }
614
615         /* after area regions so we can do area 'overlay' drawing */
616         ED_screen_draw(win);
617
618         /* draw overlapping regions */
619         for(ar=screen->regionbase.first; ar; ar= ar->next) {
620                 if(ar->swinid) {
621                         CTX_wm_menu_set(C, ar);
622                         ED_region_do_draw(C, ar);
623                         CTX_wm_menu_set(C, NULL);
624                         /* when a menu is being drawn, don't do the paint cursors */
625                         paintcursor= 0;
626                 }
627         }
628
629         /* always draw, not only when screen tagged */
630         if(win->gesture.first)
631                 wm_gesture_draw(win);
632
633         if(paintcursor && wm->paintcursors.first) {
634                 for(sa= screen->areabase.first; sa; sa= sa->next) {
635                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
636                                 if(ar->swinid == screen->subwinactive) {
637                                         CTX_wm_area_set(C, sa);
638                                         CTX_wm_region_set(C, ar);
639
640                                         /* make region ready for draw, scissor, pixelspace */
641                                         ED_region_set(C, ar);
642                                         wm_paintcursor_draw(C, ar);
643
644                                         CTX_wm_region_set(C, NULL);
645                                         CTX_wm_area_set(C, NULL);
646                                 }
647                         }
648                 }
649
650                 wmSubWindowSet(win, screen->mainwin);
651         }
652         
653         /* needs pixel coords in screen */
654         if(wm->drags.first) {
655                 wm_drags_draw(C, win, NULL);
656         }
657
658 }
659
660 /****************** main update call **********************/
661
662 /* quick test to prevent changing window drawable */
663 static int wm_draw_update_test_window(wmWindow *win)
664 {
665         ScrArea *sa;
666         ARegion *ar;
667
668         for(ar= win->screen->regionbase.first; ar; ar= ar->next) {
669                 if(ar->do_draw_overlay) {
670                         wm_tag_redraw_overlay(win, ar);
671                         ar->do_draw_overlay= 0;
672                 }
673         }
674         
675         if(win->screen->do_refresh)
676                 return 1;
677         if(win->screen->do_draw)
678                 return 1;
679         if(win->screen->do_draw_gesture)
680                 return 1;
681         if(win->screen->do_draw_paintcursor)
682                 return 1;
683         if(win->screen->do_draw_drag)
684                 return 1;
685         
686         for(ar= win->screen->regionbase.first; ar; ar= ar->next)
687                 if(ar->swinid && ar->do_draw)
688                         return 1;
689                 
690         for(sa= win->screen->areabase.first; sa; sa= sa->next)
691                 for(ar=sa->regionbase.first; ar; ar= ar->next)
692                         if(ar->swinid && ar->do_draw)
693                                 return 1;
694
695         return 0;
696 }
697
698 static int wm_automatic_draw_method(wmWindow *win)
699 {
700         /* Ideally all cards would work well with triple buffer, since if it works
701            well gives the least redraws and is considerably faster at partial redraw
702            for sculpting or drawing overlapping menus. For typically lower end cards
703            copy to texture is slow though and so we use overlap instead there. */
704
705         if(win->drawmethod == USER_DRAW_AUTOMATIC) {
706                 /* ATI opensource driver is known to be very slow at this */
707                 if(GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
708                         return USER_DRAW_OVERLAP;
709                 /* also Intel drivers are slow */
710                 else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY))
711                         return USER_DRAW_OVERLAP;
712                 else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY))
713                         return USER_DRAW_OVERLAP_FLIP;
714                 else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY))
715                         return USER_DRAW_OVERLAP_FLIP;
716                 /* Windows software driver darkens color on each redraw */
717                 else if(GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
718                         return USER_DRAW_OVERLAP_FLIP;
719                 else if(GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
720                         return USER_DRAW_OVERLAP;
721                 /* drawing lower color depth again degrades colors each time */
722                 else if(GPU_color_depth() < 24)
723                         return USER_DRAW_OVERLAP;
724                 else
725                         return USER_DRAW_TRIPLE;
726         }
727         else
728                 return win->drawmethod;
729 }
730
731 void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
732 {
733         /* for draw triple gestures, paint cursors don't need region redraw */
734         if(ar && win) {
735                 if(wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
736                         ED_region_tag_redraw(ar);
737                 win->screen->do_draw_paintcursor= 1;
738         }
739 }
740
741 void wm_draw_update(bContext *C)
742 {
743         wmWindowManager *wm= CTX_wm_manager(C);
744         wmWindow *win;
745         int drawmethod;
746
747         GPU_free_unused_buffers();
748         
749         for(win= wm->windows.first; win; win= win->next) {
750                 if(win->drawmethod != U.wmdrawmethod) {
751                         wm_draw_window_clear(win);
752                         win->drawmethod= U.wmdrawmethod;
753                 }
754
755                 if(wm_draw_update_test_window(win)) {
756                         CTX_wm_window_set(C, win);
757                         
758                         /* sets context window+screen */
759                         wm_window_make_drawable(C, win);
760
761                         /* notifiers for screen redraw */
762                         if(win->screen->do_refresh)
763                                 ED_screen_refresh(wm, win);
764
765                         drawmethod= wm_automatic_draw_method(win);
766
767                         if(win->drawfail)
768                                 wm_method_draw_overlap_all(C, win, 0);
769                         else if(drawmethod == USER_DRAW_FULL)
770                                 wm_method_draw_full(C, win);
771                         else if(drawmethod == USER_DRAW_OVERLAP)
772                                 wm_method_draw_overlap_all(C, win, 0);
773                         else if(drawmethod == USER_DRAW_OVERLAP_FLIP)
774                                 wm_method_draw_overlap_all(C, win, 1);
775                         else // if(drawmethod == USER_DRAW_TRIPLE)
776                                 wm_method_draw_triple(C, win);
777
778                         win->screen->do_draw_gesture= 0;
779                         win->screen->do_draw_paintcursor= 0;
780                         win->screen->do_draw_drag= 0;
781                 
782                         wm_window_swap_buffers(win);
783
784                         CTX_wm_window_set(C, NULL);
785                 }
786         }
787 }
788
789 void wm_draw_window_clear(wmWindow *win)
790 {
791         bScreen *screen= win->screen;
792         ScrArea *sa;
793         ARegion *ar;
794         int drawmethod= wm_automatic_draw_method(win);
795
796         if(drawmethod == USER_DRAW_TRIPLE)
797                 wm_draw_triple_free(win);
798
799         /* clear screen swap flags */
800         if(screen) {
801                 for(sa= screen->areabase.first; sa; sa= sa->next)
802                         for(ar=sa->regionbase.first; ar; ar= ar->next)
803                                 ar->swap= WIN_NONE_OK;
804                 
805                 screen->swap= WIN_NONE_OK;
806         }
807 }
808
809 void wm_draw_region_clear(wmWindow *win, ARegion *ar)
810 {
811         int drawmethod= wm_automatic_draw_method(win);
812
813         if(ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
814                 wm_flush_regions_down(win->screen, &ar->winrct);
815
816         win->screen->do_draw= 1;
817 }
818