Blender V2.61 - r43446
|
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