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