Blender V2.61 - r43446

wm_draw.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2007 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Blender Foundation
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <GL/glew.h>
00035 
00036 #include "DNA_listBase.h"
00037 #include "DNA_screen_types.h"
00038 #include "DNA_windowmanager_types.h"
00039 #include "DNA_userdef_types.h"
00040 #include "DNA_view3d_types.h"
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "BLI_blenlib.h"
00045 #include "BLI_utildefines.h"
00046 #include "BLI_math_base.h"
00047 
00048 #include "BKE_context.h"
00049 #include "BKE_global.h"
00050 
00051 
00052 #include "GHOST_C-api.h"
00053 
00054 #include "ED_screen.h"
00055 
00056 #include "GPU_draw.h"
00057 #include "GPU_extensions.h"
00058 
00059 #include "RE_engine.h"
00060 
00061 #include "WM_api.h"
00062 #include "WM_types.h"
00063 #include "wm.h"
00064 #include "wm_draw.h"
00065 #include "wm_window.h"
00066 #include "wm_event_system.h"
00067 
00068 /* swap */
00069 #define WIN_NONE_OK     0
00070 #define WIN_BACK_OK     1
00071 #define WIN_FRONT_OK    2
00072 #define WIN_BOTH_OK     3
00073 
00074 /* ******************* drawing, overlays *************** */
00075 
00076 
00077 static void wm_paintcursor_draw(bContext *C, ARegion *ar)
00078 {
00079     wmWindowManager *wm= CTX_wm_manager(C);
00080     
00081     if(wm->paintcursors.first) {
00082         wmWindow *win= CTX_wm_window(C);
00083         bScreen *screen= win->screen;
00084         wmPaintCursor *pc;
00085 
00086         if(screen->subwinactive == ar->swinid) {
00087             for(pc= wm->paintcursors.first; pc; pc= pc->next) {
00088                 if(pc->poll == NULL || pc->poll(C)) {
00089                     ARegion *ar_other= CTX_wm_region(C);
00090                     if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
00091                         int x = 0, y = 0;
00092                         wm_get_cursor_position(win, &x, &y);
00093                         pc->draw(C, x - ar_other->winrct.xmin, y - ar_other->winrct.ymin, pc->customdata);
00094                     } else {
00095                         pc->draw(C, win->eventstate->x - ar_other->winrct.xmin, win->eventstate->y - ar_other->winrct.ymin, pc->customdata);
00096                     }
00097                 }
00098             }
00099         }
00100     }
00101 }
00102 
00103 /* ********************* drawing, swap ****************** */
00104 
00105 static void wm_area_mark_invalid_backbuf(ScrArea *sa)
00106 {
00107     if(sa->spacetype == SPACE_VIEW3D)
00108         ((View3D*)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
00109 }
00110 
00111 static int wm_area_test_invalid_backbuf(ScrArea *sa)
00112 {
00113     if(sa->spacetype == SPACE_VIEW3D)
00114         return (((View3D*)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF);
00115     else
00116         return 1;
00117 }
00118 
00119 static void wm_region_test_render_do_draw(ScrArea *sa, ARegion *ar)
00120 {
00121     if(sa->spacetype == SPACE_VIEW3D) {
00122         RegionView3D *rv3d = ar->regiondata;
00123         RenderEngine *engine = (rv3d)? rv3d->render_engine: NULL;
00124 
00125         if(engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
00126             ar->do_draw = 1;
00127             engine->flag &= ~RE_ENGINE_DO_DRAW;
00128         }
00129     }
00130 }
00131 
00132 /********************** draw all **************************/
00133 /* - reference method, draw all each time                 */
00134 
00135 static void wm_method_draw_full(bContext *C, wmWindow *win)
00136 {
00137     bScreen *screen= win->screen;
00138     ScrArea *sa;
00139     ARegion *ar;
00140 
00141     /* draw area regions */
00142     for(sa= screen->areabase.first; sa; sa= sa->next) {
00143         CTX_wm_area_set(C, sa);
00144 
00145         for(ar=sa->regionbase.first; ar; ar= ar->next) {
00146             if(ar->swinid) {
00147                 CTX_wm_region_set(C, ar);
00148                 ED_region_do_draw(C, ar);
00149                 wm_paintcursor_draw(C, ar);
00150                 ED_area_overdraw_flush(sa, ar);
00151                 CTX_wm_region_set(C, NULL);
00152             }
00153         }
00154         
00155         wm_area_mark_invalid_backbuf(sa);
00156         CTX_wm_area_set(C, NULL);
00157     }
00158 
00159     ED_screen_draw(win);
00160     ED_area_overdraw(C);
00161 
00162     /* draw overlapping regions */
00163     for(ar=screen->regionbase.first; ar; ar= ar->next) {
00164         if(ar->swinid) {
00165             CTX_wm_menu_set(C, ar);
00166             ED_region_do_draw(C, ar);
00167             CTX_wm_menu_set(C, NULL);
00168         }
00169     }
00170 
00171     if(screen->do_draw_gesture)
00172         wm_gesture_draw(win);
00173 }
00174 
00175 /****************** draw overlap all **********************/
00176 /* - redraw marked areas, and anything that overlaps it   */
00177 /* - it also handles swap exchange optionally, assuming   */
00178 /*   that on swap no clearing happens and we get back the */
00179 /*   same buffer as we swapped to the front               */
00180 
00181 /* mark area-regions to redraw if overlapped with rect */
00182 static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
00183 {
00184     ScrArea *sa;
00185     ARegion *ar;
00186 
00187     for(sa= screen->areabase.first; sa; sa= sa->next) {
00188         for(ar= sa->regionbase.first; ar; ar= ar->next) {
00189             if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
00190                 ar->do_draw= RGN_DRAW;
00191                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
00192                 ar->swap= WIN_NONE_OK;
00193             }
00194         }
00195     }
00196 }
00197 
00198 /* mark menu-regions to redraw if overlapped with rect */
00199 static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
00200 {
00201     ARegion *ar;
00202     
00203     for(ar= screen->regionbase.first; ar; ar= ar->next) {
00204         if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
00205             ar->do_draw= RGN_DRAW;
00206             memset(&ar->drawrct, 0, sizeof(ar->drawrct));
00207             ar->swap= WIN_NONE_OK;
00208         }
00209     }
00210 }
00211 
00212 static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
00213 {
00214     wmWindowManager *wm= CTX_wm_manager(C);
00215     bScreen *screen= win->screen;
00216     ScrArea *sa;
00217     ARegion *ar;
00218     static rcti rect= {0, 0, 0, 0};
00219 
00220     /* after backbuffer selection draw, we need to redraw */
00221     for(sa= screen->areabase.first; sa; sa= sa->next)
00222         for(ar= sa->regionbase.first; ar; ar= ar->next)
00223             if(ar->swinid && !wm_area_test_invalid_backbuf(sa))
00224                 ED_region_tag_redraw(ar);
00225 
00226     /* flush overlapping regions */
00227     if(screen->regionbase.first) {
00228         /* flush redraws of area regions up to overlapping regions */
00229         for(sa= screen->areabase.first; sa; sa= sa->next)
00230             for(ar= sa->regionbase.first; ar; ar= ar->next)
00231                 if(ar->swinid && ar->do_draw)
00232                     wm_flush_regions_up(screen, &ar->winrct);
00233         
00234         /* flush between overlapping regions */
00235         for(ar= screen->regionbase.last; ar; ar= ar->prev)
00236             if(ar->swinid && ar->do_draw)
00237                 wm_flush_regions_up(screen, &ar->winrct);
00238         
00239         /* flush redraws of overlapping regions down to area regions */
00240         for(ar= screen->regionbase.last; ar; ar= ar->prev)
00241             if(ar->swinid && ar->do_draw)
00242                 wm_flush_regions_down(screen, &ar->winrct);
00243     }
00244 
00245     /* flush drag item */
00246     if(rect.xmin!=rect.xmax) {
00247         wm_flush_regions_down(screen, &rect);
00248         rect.xmin= rect.xmax = 0;
00249     }
00250     if(wm->drags.first) {
00251         /* doesnt draw, fills rect with boundbox */
00252         wm_drags_draw(C, win, &rect);
00253     }
00254     
00255     /* draw marked area regions */
00256     for(sa= screen->areabase.first; sa; sa= sa->next) {
00257         CTX_wm_area_set(C, sa);
00258 
00259         for(ar=sa->regionbase.first; ar; ar= ar->next) {
00260             if(ar->swinid) {
00261                 if(ar->do_draw) {
00262                     CTX_wm_region_set(C, ar);
00263                     ED_region_do_draw(C, ar);
00264                     wm_paintcursor_draw(C, ar);
00265                     ED_area_overdraw_flush(sa, ar);
00266                     CTX_wm_region_set(C, NULL);
00267 
00268                     if(exchange)
00269                         ar->swap= WIN_FRONT_OK;
00270                 }
00271                 else if(exchange) {
00272                     if(ar->swap == WIN_FRONT_OK) {
00273                         CTX_wm_region_set(C, ar);
00274                         ED_region_do_draw(C, ar);
00275                         wm_paintcursor_draw(C, ar);
00276                         ED_area_overdraw_flush(sa, ar);
00277                         CTX_wm_region_set(C, NULL);
00278 
00279                         ar->swap= WIN_BOTH_OK;
00280                     }
00281                     else if(ar->swap == WIN_BACK_OK)
00282                         ar->swap= WIN_FRONT_OK;
00283                     else if(ar->swap == WIN_BOTH_OK)
00284                         ar->swap= WIN_BOTH_OK;
00285                 }
00286             }
00287         }
00288         
00289         wm_area_mark_invalid_backbuf(sa);
00290         CTX_wm_area_set(C, NULL);
00291     }
00292 
00293     /* after area regions so we can do area 'overlay' drawing */
00294     if(screen->do_draw) {
00295         ED_screen_draw(win);
00296 
00297         if(exchange)
00298             screen->swap= WIN_FRONT_OK;
00299     }
00300     else if(exchange) {
00301         if(screen->swap==WIN_FRONT_OK) {
00302             ED_screen_draw(win);
00303             screen->swap= WIN_BOTH_OK;
00304         }
00305         else if(screen->swap==WIN_BACK_OK)
00306             screen->swap= WIN_FRONT_OK;
00307         else if(screen->swap==WIN_BOTH_OK)
00308             screen->swap= WIN_BOTH_OK;
00309     }
00310 
00311     ED_area_overdraw(C);
00312 
00313     /* draw marked overlapping regions */
00314     for(ar=screen->regionbase.first; ar; ar= ar->next) {
00315         if(ar->swinid && ar->do_draw) {
00316             CTX_wm_menu_set(C, ar);
00317             ED_region_do_draw(C, ar);
00318             CTX_wm_menu_set(C, NULL);
00319         }
00320     }
00321 
00322     if(screen->do_draw_gesture)
00323         wm_gesture_draw(win);
00324     
00325     /* needs pixel coords in screen */
00326     if(wm->drags.first) {
00327         wm_drags_draw(C, win, NULL);
00328     }
00329 }
00330 
00331 #if 0
00332 /******************** draw damage ************************/
00333 /* - not implemented                                      */
00334 
00335 static void wm_method_draw_damage(bContext *C, wmWindow *win)
00336 {
00337     wm_method_draw_all(C, win);
00338 }
00339 #endif
00340 
00341 /****************** draw triple buffer ********************/
00342 /* - area regions are written into a texture, without any */
00343 /*   of the overlapping menus, brushes, gestures. these   */
00344 /*   are redrawn each time.                               */
00345 /*                                                        */
00346 /* - if non-power of two textures are supported, that is  */
00347 /*   used. if not, multiple smaller ones are used, with   */
00348 /*   worst case wasted space being 23.4% for 3x3 textures */
00349 
00350 #define MAX_N_TEX 3
00351 
00352 typedef struct wmDrawTriple {
00353     GLuint bind[MAX_N_TEX*MAX_N_TEX];
00354     int x[MAX_N_TEX], y[MAX_N_TEX];
00355     int nx, ny;
00356     GLenum target;
00357 } wmDrawTriple;
00358 
00359 static void split_width(int x, int n, int *splitx, int *nx)
00360 {
00361     int a, newnx, waste;
00362 
00363     /* if already power of two just use it */
00364     if(is_power_of_2_i(x)) {
00365         splitx[0]= x;
00366         (*nx)++;
00367         return;
00368     }
00369 
00370     if(n == 1) {
00371         /* last part, we have to go larger */
00372         splitx[0]= power_of_2_max_i(x);
00373         (*nx)++;
00374     }
00375     else {
00376         /* two or more parts to go, use smaller part */
00377         splitx[0]= power_of_2_min_i(x);
00378         newnx= ++(*nx);
00379         split_width(x-splitx[0], n-1, splitx+1, &newnx);
00380 
00381         for(waste=0, a=0; a<n; a++)
00382             waste += splitx[a];
00383 
00384         /* if we waste more space or use the same amount,
00385          * revert deeper splits and just use larger */
00386         if(waste >= power_of_2_max_i(x)) {
00387             splitx[0]= power_of_2_max_i(x);
00388             memset(splitx+1, 0, sizeof(int)*(n-1));
00389         }
00390         else
00391             *nx= newnx;
00392     }
00393 }
00394 
00395 static void wm_draw_triple_free(wmWindow *win)
00396 {
00397     if(win->drawdata) {
00398         wmDrawTriple *triple= win->drawdata;
00399 
00400         glDeleteTextures(triple->nx*triple->ny, triple->bind);
00401 
00402         MEM_freeN(triple);
00403 
00404         win->drawdata= NULL;
00405     }
00406 }
00407 
00408 static void wm_draw_triple_fail(bContext *C, wmWindow *win)
00409 {
00410     wm_draw_window_clear(win);
00411 
00412     win->drawfail= 1;
00413     wm_method_draw_overlap_all(C, win, 0);
00414 }
00415 
00416 static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
00417 {
00418     GLint maxsize;
00419     int x, y;
00420 
00421     /* compute texture sizes */
00422     if(GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
00423         triple->target= GL_TEXTURE_RECTANGLE_ARB;
00424         triple->nx= 1;
00425         triple->ny= 1;
00426         triple->x[0]= win->sizex;
00427         triple->y[0]= win->sizey;
00428     }
00429     else if(GPU_non_power_of_two_support()) {
00430         triple->target= GL_TEXTURE_2D;
00431         triple->nx= 1;
00432         triple->ny= 1;
00433         triple->x[0]= win->sizex;
00434         triple->y[0]= win->sizey;
00435     }
00436     else {
00437         triple->target= GL_TEXTURE_2D;
00438         triple->nx= 0;
00439         triple->ny= 0;
00440         split_width(win->sizex, MAX_N_TEX, triple->x, &triple->nx);
00441         split_width(win->sizey, MAX_N_TEX, triple->y, &triple->ny);
00442     }
00443 
00444     /* generate texture names */
00445     glGenTextures(triple->nx*triple->ny, triple->bind);
00446 
00447     if(!triple->bind[0]) {
00448         /* not the typical failure case but we handle it anyway */
00449         printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
00450         return 0;
00451     }
00452 
00453     for(y=0; y<triple->ny; y++) {
00454         for(x=0; x<triple->nx; x++) {
00455             /* proxy texture is only guaranteed to test for the cases that
00456              * there is only one texture in use, which may not be the case */
00457             glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
00458 
00459             if(triple->x[x] > maxsize || triple->y[y] > maxsize) {
00460                 glBindTexture(triple->target, 0);
00461                 printf("WM: failed to allocate texture for triple buffer drawing (texture too large for graphics card).\n");
00462                 return 0;
00463             }
00464 
00465             /* setup actual texture */
00466             glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
00467             glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
00468             glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00469             glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00470             // glColor still used with this enabled?
00471             // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00472             glBindTexture(triple->target, 0);
00473 
00474             /* not sure if this works everywhere .. */
00475             if(glGetError() == GL_OUT_OF_MEMORY) {
00476                 printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
00477                 return 0;
00478             }
00479         }
00480     }
00481 
00482     return 1;
00483 }
00484 
00485 static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple)
00486 {
00487     float halfx, halfy, ratiox, ratioy;
00488     int x, y, sizex, sizey, offx, offy;
00489 
00490     glEnable(triple->target);
00491 
00492     for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
00493         for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
00494             sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
00495             sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
00496 
00497             /* wmOrtho for the screen has this same offset */
00498             ratiox= sizex;
00499             ratioy= sizey;
00500             halfx= 0.375f;
00501             halfy= 0.375f;
00502 
00503             /* texture rectangle has unnormalized coordinates */
00504             if(triple->target == GL_TEXTURE_2D) {
00505                 ratiox /= triple->x[x];
00506                 ratioy /= triple->y[y];
00507                 halfx /= triple->x[x];
00508                 halfy /= triple->y[y];
00509             }
00510 
00511             glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
00512 
00513             glColor3f(1.0f, 1.0f, 1.0f);
00514             glBegin(GL_QUADS);
00515                 glTexCoord2f(halfx, halfy);
00516                 glVertex2f(offx, offy);
00517 
00518                 glTexCoord2f(ratiox+halfx, halfy);
00519                 glVertex2f(offx+sizex, offy);
00520 
00521                 glTexCoord2f(ratiox+halfx, ratioy+halfy);
00522                 glVertex2f(offx+sizex, offy+sizey);
00523 
00524                 glTexCoord2f(halfx, ratioy+halfy);
00525                 glVertex2f(offx, offy+sizey);
00526             glEnd();
00527         }
00528     }
00529 
00530     glBindTexture(triple->target, 0);
00531     glDisable(triple->target);
00532 }
00533 
00534 static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
00535 {
00536     int x, y, sizex, sizey, offx, offy;
00537 
00538     for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
00539         for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
00540             sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
00541             sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
00542 
00543             glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
00544             glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey);
00545         }
00546     }
00547 
00548     glBindTexture(triple->target, 0);
00549 }
00550 
00551 static void wm_method_draw_triple(bContext *C, wmWindow *win)
00552 {
00553     wmWindowManager *wm= CTX_wm_manager(C);
00554     wmDrawTriple *triple;
00555     bScreen *screen= win->screen;
00556     ScrArea *sa;
00557     ARegion *ar;
00558     int copytex= 0, paintcursor= 1;
00559 
00560     if(win->drawdata) {
00561         glClearColor(0, 0, 0, 0);
00562         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
00563 
00564         wmSubWindowSet(win, screen->mainwin);
00565 
00566         wm_triple_draw_textures(win, win->drawdata);
00567     }
00568     else {
00569         win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
00570 
00571         if(!wm_triple_gen_textures(win, win->drawdata))
00572         {
00573             wm_draw_triple_fail(C, win);
00574             return;
00575         }
00576     }
00577 
00578     triple= win->drawdata;
00579 
00580     /* draw marked area regions */
00581     for(sa= screen->areabase.first; sa; sa= sa->next) {
00582         CTX_wm_area_set(C, sa);
00583 
00584         for(ar=sa->regionbase.first; ar; ar= ar->next) {
00585             if(ar->swinid && ar->do_draw) {
00586                 CTX_wm_region_set(C, ar);
00587                 ED_region_do_draw(C, ar);
00588                 ED_area_overdraw_flush(sa, ar);
00589                 CTX_wm_region_set(C, NULL);
00590                 copytex= 1;
00591             }
00592         }
00593         
00594         wm_area_mark_invalid_backbuf(sa);
00595         CTX_wm_area_set(C, NULL);
00596     }
00597 
00598     if(copytex) {
00599         wmSubWindowSet(win, screen->mainwin);
00600         ED_area_overdraw(C);
00601 
00602         wm_triple_copy_textures(win, triple);
00603     }
00604 
00605     /* after area regions so we can do area 'overlay' drawing */
00606     ED_screen_draw(win);
00607 
00608     /* draw overlapping regions */
00609     for(ar=screen->regionbase.first; ar; ar= ar->next) {
00610         if(ar->swinid) {
00611             CTX_wm_menu_set(C, ar);
00612             ED_region_do_draw(C, ar);
00613             CTX_wm_menu_set(C, NULL);
00614             /* when a menu is being drawn, don't do the paint cursors */
00615             paintcursor= 0;
00616         }
00617     }
00618 
00619     /* always draw, not only when screen tagged */
00620     if(win->gesture.first)
00621         wm_gesture_draw(win);
00622 
00623     if(paintcursor && wm->paintcursors.first) {
00624         for(sa= screen->areabase.first; sa; sa= sa->next) {
00625             for(ar=sa->regionbase.first; ar; ar= ar->next) {
00626                 if(ar->swinid == screen->subwinactive) {
00627                     CTX_wm_area_set(C, sa);
00628                     CTX_wm_region_set(C, ar);
00629 
00630                     /* make region ready for draw, scissor, pixelspace */
00631                     ED_region_set(C, ar);
00632                     wm_paintcursor_draw(C, ar);
00633 
00634                     CTX_wm_region_set(C, NULL);
00635                     CTX_wm_area_set(C, NULL);
00636                 }
00637             }
00638         }
00639 
00640         wmSubWindowSet(win, screen->mainwin);
00641     }
00642     
00643     /* needs pixel coords in screen */
00644     if(wm->drags.first) {
00645         wm_drags_draw(C, win, NULL);
00646     }
00647 
00648 }
00649 
00650 /****************** main update call **********************/
00651 
00652 /* quick test to prevent changing window drawable */
00653 static int wm_draw_update_test_window(wmWindow *win)
00654 {
00655     ScrArea *sa;
00656     ARegion *ar;
00657     int do_draw= 0;
00658 
00659     for(ar= win->screen->regionbase.first; ar; ar= ar->next) {
00660         if(ar->do_draw_overlay) {
00661             wm_tag_redraw_overlay(win, ar);
00662             ar->do_draw_overlay= 0;
00663         }
00664         if(ar->swinid && ar->do_draw)
00665             do_draw= 1;
00666     }
00667 
00668     for(sa= win->screen->areabase.first; sa; sa= sa->next) {
00669         for(ar=sa->regionbase.first; ar; ar= ar->next) {
00670             wm_region_test_render_do_draw(sa, ar);
00671 
00672             if(ar->swinid && ar->do_draw)
00673                 do_draw = 1;
00674         }
00675     }
00676 
00677     if(do_draw)
00678         return 1;
00679     
00680     if(win->screen->do_refresh)
00681         return 1;
00682     if(win->screen->do_draw)
00683         return 1;
00684     if(win->screen->do_draw_gesture)
00685         return 1;
00686     if(win->screen->do_draw_paintcursor)
00687         return 1;
00688     if(win->screen->do_draw_drag)
00689         return 1;
00690     
00691     return 0;
00692 }
00693 
00694 static int wm_automatic_draw_method(wmWindow *win)
00695 {
00696     /* Ideally all cards would work well with triple buffer, since if it works
00697        well gives the least redraws and is considerably faster at partial redraw
00698        for sculpting or drawing overlapping menus. For typically lower end cards
00699        copy to texture is slow though and so we use overlap instead there. */
00700 
00701     if(win->drawmethod == USER_DRAW_AUTOMATIC) {
00702         /* ATI opensource driver is known to be very slow at this */
00703         if(GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
00704             return USER_DRAW_OVERLAP;
00705         /* also Intel drivers are slow */
00706         else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY))
00707             return USER_DRAW_OVERLAP;
00708         else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY))
00709             return USER_DRAW_OVERLAP_FLIP;
00710         else if(GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY))
00711             return USER_DRAW_OVERLAP_FLIP;
00712         /* Windows software driver darkens color on each redraw */
00713         else if(GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
00714             return USER_DRAW_OVERLAP_FLIP;
00715         else if(GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
00716             return USER_DRAW_OVERLAP;
00717         /* drawing lower color depth again degrades colors each time */
00718         else if(GPU_color_depth() < 24)
00719             return USER_DRAW_OVERLAP;
00720         else
00721             return USER_DRAW_TRIPLE;
00722     }
00723     else
00724         return win->drawmethod;
00725 }
00726 
00727 void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
00728 {
00729     /* for draw triple gestures, paint cursors don't need region redraw */
00730     if(ar && win) {
00731         if(wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
00732             ED_region_tag_redraw(ar);
00733         win->screen->do_draw_paintcursor= 1;
00734     }
00735 }
00736 
00737 void wm_draw_update(bContext *C)
00738 {
00739     wmWindowManager *wm= CTX_wm_manager(C);
00740     wmWindow *win;
00741     int drawmethod;
00742 
00743     GPU_free_unused_buffers();
00744     
00745     for(win= wm->windows.first; win; win= win->next) {
00746         if(win->drawmethod != U.wmdrawmethod) {
00747             wm_draw_window_clear(win);
00748             win->drawmethod= U.wmdrawmethod;
00749         }
00750 
00751         if(wm_draw_update_test_window(win)) {
00752             CTX_wm_window_set(C, win);
00753             
00754             /* sets context window+screen */
00755             wm_window_make_drawable(C, win);
00756 
00757             /* notifiers for screen redraw */
00758             if(win->screen->do_refresh)
00759                 ED_screen_refresh(wm, win);
00760 
00761             drawmethod= wm_automatic_draw_method(win);
00762 
00763             if(win->drawfail)
00764                 wm_method_draw_overlap_all(C, win, 0);
00765             else if(drawmethod == USER_DRAW_FULL)
00766                 wm_method_draw_full(C, win);
00767             else if(drawmethod == USER_DRAW_OVERLAP)
00768                 wm_method_draw_overlap_all(C, win, 0);
00769             else if(drawmethod == USER_DRAW_OVERLAP_FLIP)
00770                 wm_method_draw_overlap_all(C, win, 1);
00771             else // if(drawmethod == USER_DRAW_TRIPLE)
00772                 wm_method_draw_triple(C, win);
00773 
00774             win->screen->do_draw_gesture= 0;
00775             win->screen->do_draw_paintcursor= 0;
00776             win->screen->do_draw_drag= 0;
00777         
00778             wm_window_swap_buffers(win);
00779 
00780             CTX_wm_window_set(C, NULL);
00781         }
00782     }
00783 }
00784 
00785 void wm_draw_window_clear(wmWindow *win)
00786 {
00787     bScreen *screen= win->screen;
00788     ScrArea *sa;
00789     ARegion *ar;
00790     int drawmethod= wm_automatic_draw_method(win);
00791 
00792     if(drawmethod == USER_DRAW_TRIPLE)
00793         wm_draw_triple_free(win);
00794 
00795     /* clear screen swap flags */
00796     if(screen) {
00797         for(sa= screen->areabase.first; sa; sa= sa->next)
00798             for(ar=sa->regionbase.first; ar; ar= ar->next)
00799                 ar->swap= WIN_NONE_OK;
00800         
00801         screen->swap= WIN_NONE_OK;
00802     }
00803 }
00804 
00805 void wm_draw_region_clear(wmWindow *win, ARegion *ar)
00806 {
00807     int drawmethod= wm_automatic_draw_method(win);
00808 
00809     if(ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
00810         wm_flush_regions_down(win->screen, &ar->winrct);
00811 
00812     win->screen->do_draw= 1;
00813 }
00814 
00815 void WM_redraw_windows(bContext *C)
00816 {
00817     wmWindow *win_prev= CTX_wm_window(C);
00818     ScrArea *area_prev= CTX_wm_area(C);
00819     ARegion *ar_prev= CTX_wm_region(C);
00820 
00821     wm_draw_update(C);
00822 
00823     CTX_wm_window_set(C, win_prev);
00824     CTX_wm_area_set(C, area_prev);
00825     CTX_wm_region_set(C, ar_prev);
00826 }
00827