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