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