Merging r46203 through r46413 from trunk into soc-2011-tomato
[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                         // The current color is ignored if the GL_REPLACE texture environment is used.
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