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