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