|
Blender
V2.59
|
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