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