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