diff options
18 files changed, 461 insertions, 149 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 54ccc66e514..0d1eba2048b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4007,8 +4007,9 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) win->handlers.first= win->handlers.last= NULL; win->subwindows.first= win->subwindows.last= NULL; - win->drawtex= 0; - win->drawmethod= 0; + win->drawdata= NULL; + win->drawmethod= -1; + win->drawfail= 0; } wm->operators.first= wm->operators.last= NULL; @@ -4459,6 +4460,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) ar->swinid= 0; ar->type= NULL; ar->swap= 0; + ar->do_draw= 0; + memset(&ar->drawrct, 0, sizeof(ar->drawrct)); } /* for the saved 2.50 files without regiondata */ @@ -4497,6 +4500,7 @@ static void direct_link_screen(FileData *fd, bScreen *sc) sc->context= NULL; sc->mainwin= sc->subwinactive= 0; /* indices */ + sc->swap= 0; /* hacky patch... but people have been saving files with the verse-blender, causing the handler to keep running for ever, with no means to disable it */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 809e7378edc..1f5f83c852b 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -41,6 +41,7 @@ struct bContext; struct SpaceType; struct AreagionType; struct uiBlock; +struct rcti; /* regions */ void ED_region_do_listen(ARegion *ar, struct wmNotifier *note); @@ -49,6 +50,7 @@ void ED_region_exit(struct bContext *C, struct ARegion *ar); void ED_region_pixelspace(struct ARegion *ar); void ED_region_init(struct bContext *C, struct ARegion *ar); void ED_region_tag_redraw(struct ARegion *ar); +void ED_region_tag_redraw_partial(struct ARegion *ar, struct rcti *rct); /* spaces */ void ED_spacetypes_init(void); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index e5443b81fa4..de4cf476967 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -45,6 +45,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "wm_draw.h" #include "wm_subwindow.h" #include "wm_window.h" @@ -237,6 +238,8 @@ ARegion *ui_add_temporary_region(bScreen *sc) void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar) { + ar->regiondata= NULL; + wm_draw_region_clear(CTX_wm_window(C), ar); ED_region_exit(C, ar); BKE_area_region_free(NULL, ar); /* NULL: no spacetype */ BLI_freelinkN(&sc->regionbase, ar); @@ -393,8 +396,6 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) void ui_tooltip_free(bContext *C, ARegion *ar) { ui_remove_temporary_region(C, CTX_wm_screen(C), ar); - - WM_event_add_notifier(C, NC_WINDOW, NULL); // XXX provide rect for window } /************************* Creating Menu Blocks **********************/ @@ -711,8 +712,6 @@ void ui_menu_block_free(bContext *C, uiMenuBlockHandle *handle) { ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region); MEM_freeN(handle); - - WM_event_add_notifier(C, NC_WINDOW, NULL); // XXX provide rect for window } /***************************** Menu Button ***************************/ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index cddc7d391c8..3f1d82b1936 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -192,9 +192,19 @@ void ED_region_do_draw(bContext *C, ARegion *ar) wmWindow *win= CTX_wm_window(C); ScrArea *sa= CTX_wm_area(C); ARegionType *at= ar->type; + + /* if no partial draw rect set, full rect */ + if(ar->drawrct.xmin == ar->drawrct.xmax) + ar->drawrct= ar->winrct; + + /* extra clip for safety */ + ar->drawrct.xmin= MAX2(ar->winrct.xmin, ar->drawrct.xmin); + ar->drawrct.ymin= MAX2(ar->winrct.ymin, ar->drawrct.ymin); + ar->drawrct.xmax= MIN2(ar->winrct.xmax, ar->drawrct.xmax); + ar->drawrct.ymax= MIN2(ar->winrct.ymax, ar->drawrct.ymax); /* note; this sets state, so we can use wmOrtho and friends */ - wmSubWindowSet(win, ar->swinid); + wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct); /* optional header info instead? */ if(ar->headerstr) { @@ -223,6 +233,7 @@ void ED_region_do_draw(bContext *C, ARegion *ar) ED_region_pixelspace(ar); ar->do_draw= 0; + memset(&ar->drawrct, 0, sizeof(ar->drawrct)); } /* ********************************** @@ -232,8 +243,29 @@ void ED_region_do_draw(bContext *C, ARegion *ar) void ED_region_tag_redraw(ARegion *ar) { - if(ar) + if(ar) { + /* zero region means full region redraw */ ar->do_draw= 1; + memset(&ar->drawrct, 0, sizeof(ar->drawrct)); + } +} + +void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct) +{ + if(ar) { + if(!ar->do_draw) { + /* no redraw set yet, set partial region */ + ar->do_draw= 1; + ar->drawrct= *rct; + } + else if(ar->drawrct.xmin != ar->drawrct.xmax) { + /* partial redraw already set, expand region */ + ar->drawrct.xmin= MIN2(ar->drawrct.xmin, rct->xmin); + ar->drawrct.ymin= MIN2(ar->drawrct.ymin, rct->ymin); + ar->drawrct.xmax= MAX2(ar->drawrct.xmax, rct->xmax); + ar->drawrct.ymax= MAX2(ar->drawrct.ymax, rct->ymax); + } + } } void ED_area_tag_redraw(ScrArea *sa) @@ -242,7 +274,7 @@ void ED_area_tag_redraw(ScrArea *sa) if(sa) for(ar= sa->regionbase.first; ar; ar= ar->next) - ar->do_draw= 1; + ED_region_tag_redraw(ar); } void ED_area_tag_refresh(ScrArea *sa) diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 0c561536d32..24b397b0b82 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -54,9 +54,10 @@ typedef struct bScreen { short full, winid; /* winid from WM, starts with 1 */ short do_draw; /* notifier for drawing edges */ short do_refresh; /* notifier for scale screen, changed screen, etc */ - short do_gesture; /* notifier for gesture draw. */ + short do_draw_gesture; /* notifier for gesture draw. */ + short do_draw_paintcursor; /* notifier for paint cursor draw. */ short swap; /* indicator to survive swap-exchange systems */ - short pad[2]; + short pad; short mainwin; /* screensize subwindow, for screenedges and global menus */ short subwinactive; /* active subwindow */ @@ -127,6 +128,7 @@ typedef struct ARegion { View2D v2d; /* 2D-View scrolling/zoom info (most regions are 2d anyways) */ rcti winrct; /* coordinates of region */ + rcti drawrct; /* runtime for partial redraw, same or smaller than winrct */ short winx, winy; /* size */ short swinid; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 85a8520bfd7..f2cc1f8017c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -215,6 +215,8 @@ typedef struct UserDef { short autokey_mode; /* autokeying mode */ short autokey_flag; /* flags for autokeying */ + + int wmdrawmethod, pad; struct ColorBand coba_weight; /* from texture.h */ } UserDef; @@ -325,6 +327,11 @@ extern UserDef U; /* from blenkernel blender.c */ #define USER_VRML_AUTOSCALE 2 #define USER_VRML_TWOSIDED 4 +/* wm draw method */ +#define USER_DRAW_OVERLAP 0 +#define USER_DRAW_TRIPLE 1 +#define USER_DRAW_FULL 2 + /* tw_flag (transform widget) */ /* gp_settings (Grease Pencil Settings) */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index b0cc98c1a6e..c974fb92978 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -99,9 +99,8 @@ typedef struct wmWindow { struct wmSubWindow *curswin; /* internal for wm_subwindow.c only */ - unsigned int drawtex; /* internal for wm_draw.c only */ - int drawtexw, drawtexh; /* internal for wm_draw.c only */ - int drawmethod; /* internal for wm_draw.c only */ + int drawmethod, drawfail; /* internal for wm_draw.c only */ + void *drawdata; /* internal for wm_draw.c only */ ListBase timers; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 64db4a5f191..24f5df4dbcf 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1513,6 +1513,12 @@ static void rna_def_userdef_system(StructRNA *srna) {2048, "AUDIO_SAMPLES_2048", "2048", "Set audio mixing buffer size to 2048 samples"}, {0, NULL, NULL, NULL}}; + static EnumPropertyItem draw_method_items[] = { + {USER_DRAW_TRIPLE, "TRIPLE_BUFFER", "Triple Buffer", "Use a third buffer for minimal redraws at the cost of more memory."}, + {USER_DRAW_OVERLAP, "OVERLAP", "Overlap", "Redraw all overlapping regions, minimal memory usage but more redraws."}, + {USER_DRAW_FULL, "FULL", "Full", "Do a full redraw each time, slow, only use for reference or when all else fails."}, + {0, NULL, NULL, NULL}}; + /* System & OpenGL */ prop= RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE); @@ -1592,6 +1598,11 @@ static void rna_def_userdef_system(StructRNA *srna) RNA_def_property_range(prop, 1, 3600); RNA_def_property_ui_text(prop, "Texture Collection Rate", "Number of seconds between each run of the GL texture garbage collector."); + prop= RNA_def_property(srna, "window_draw_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "wmdrawmethod"); + RNA_def_property_enum_items(prop, draw_method_items); + RNA_def_property_ui_text(prop, "Window Draw Method", "Drawing method used by the window manager."); + prop= RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mixbufsize"); RNA_def_property_enum_items(prop, audio_mixing_samples_items); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9584751a775..7921ad8c608 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -155,7 +155,8 @@ struct wmGesture *WM_gesture_new(struct bContext *C, struct wmEvent *event, int void WM_gesture_end(struct bContext *C, struct wmGesture *gesture); /* OpenGL wrappers, mimicking opengl syntax */ -void wmSubWindowSet (struct wmWindow *win, int swinid); +void wmSubWindowSet (struct wmWindow *win, int swinid); +void wmSubWindowScissorSet (struct wmWindow *win, int swinid, struct rcti *srct); void wmLoadMatrix (float mat[][4]); void wmGetMatrix (float mat[][4]); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index f76bfb511b3..164a49ac63d 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -44,6 +44,7 @@ #include "wm_window.h" #include "wm_event_system.h" #include "wm_event_types.h" +#include "wm_draw.h" #include "wm.h" #include "ED_screen.h" diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 8537c745303..643a1370f80 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -47,6 +47,7 @@ #include "WM_api.h" #include "WM_types.h" #include "wm.h" +#include "wm_draw.h" #include "wm_window.h" #include "wm_event_system.h" @@ -56,26 +57,23 @@ #define WIN_FRONT_OK 2 #define WIN_BOTH_OK 3 -/* draw method */ -#define USER_DRAW_ALL 0 -#define USER_DRAW_OVERLAP_ALL 1 -#define USER_DRAW_OVERLAP 2 -#define USER_DRAW_TRIPLE 3 - /* ********************* drawing, swap ****************** */ -static void wm_paintcursor_draw(bContext *C) +static void wm_paintcursor_draw(bContext *C, ARegion *ar) { wmWindowManager *wm= CTX_wm_manager(C); if(wm->paintcursors.first) { wmWindow *win= CTX_wm_window(C); + bScreen *screen= win->screen; wmPaintCursor *pc; - - for(pc= wm->paintcursors.first; pc; pc= pc->next) { - if(pc->poll(C)) { - ARegion *ar= CTX_wm_region(C); - pc->draw(C, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin); + + if(screen->subwinactive == ar->swinid) { + for(pc= wm->paintcursors.first; pc; pc= pc->next) { + if(pc->poll(C)) { + ARegion *ar= CTX_wm_region(C); + pc->draw(C, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin); + } } } } @@ -84,7 +82,7 @@ static void wm_paintcursor_draw(bContext *C) /********************** draw all **************************/ /* - reference method, draw all each time */ -static void wm_method_draw_all(bContext *C, wmWindow *win) +static void wm_method_draw_full(bContext *C, wmWindow *win) { bScreen *screen= win->screen; ScrArea *sa; @@ -98,8 +96,7 @@ static void wm_method_draw_all(bContext *C, wmWindow *win) if(ar->swinid) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); - if(screen->subwinactive==ar->swinid) - wm_paintcursor_draw(C); + wm_paintcursor_draw(C, ar); ED_area_overdraw_flush(C, sa, ar); CTX_wm_region_set(C, NULL); } @@ -120,7 +117,7 @@ static void wm_method_draw_all(bContext *C, wmWindow *win) } } - if(screen->do_gesture) + if(screen->do_draw_gesture) wm_gesture_draw(win); } @@ -129,12 +126,9 @@ static void wm_method_draw_all(bContext *C, wmWindow *win) /* - it also handles swap exchange optionally, assuming */ /* that on swap no clearing happens and we get back the */ /* same buffer as we swapped to the front */ -/* - TODO for swap exchange in full screen mode, and then */ -/* switching to another window seems to invalidate the */ -/* swap flags, probably best to clear then? */ /* mark area-regions to redraw if overlapped with rect */ -static void wm_overlap_regions_down(bScreen *screen, rcti *dirty) +static void wm_flush_regions_down(bScreen *screen, rcti *dirty) { ScrArea *sa; ARegion *ar; @@ -143,6 +137,7 @@ static void wm_overlap_regions_down(bScreen *screen, rcti *dirty) for(ar= sa->regionbase.first; ar; ar= ar->next) { if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) { ar->do_draw= 1; + memset(&ar->drawrct, 0, sizeof(ar->drawrct)); ar->swap= WIN_NONE_OK; } } @@ -150,13 +145,14 @@ static void wm_overlap_regions_down(bScreen *screen, rcti *dirty) } /* mark menu-regions to redraw if overlapped with rect */ -static void wm_overlap_regions_up(bScreen *screen, rcti *dirty) +static void wm_flush_regions_up(bScreen *screen, rcti *dirty) { ARegion *ar; for(ar= screen->regionbase.first; ar; ar= ar->next) { if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) { ar->do_draw= 1; + memset(&ar->drawrct, 0, sizeof(ar->drawrct)); ar->swap= WIN_NONE_OK; } } @@ -175,17 +171,17 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win) for(sa= screen->areabase.first; sa; sa= sa->next) for(ar= sa->regionbase.first; ar; ar= ar->next) if(ar->swinid && ar->do_draw) - wm_overlap_regions_up(screen, &ar->winrct); + wm_flush_regions_up(screen, &ar->winrct); /* flush between overlapping regions */ for(ar= screen->regionbase.last; ar; ar= ar->prev) if(ar->swinid && ar->do_draw) - wm_overlap_regions_up(screen, &ar->winrct); + wm_flush_regions_up(screen, &ar->winrct); /* flush redraws of overlapping regions down to area regions */ for(ar= screen->regionbase.last; ar; ar= ar->prev) if(ar->swinid && ar->do_draw) - wm_overlap_regions_down(screen, &ar->winrct); + wm_flush_regions_down(screen, &ar->winrct); } /* draw marked area regions */ @@ -197,8 +193,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win) if(ar->do_draw) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); - if(screen->subwinactive==ar->swinid) - wm_paintcursor_draw(C); + wm_paintcursor_draw(C, ar); ED_area_overdraw_flush(C, sa, ar); CTX_wm_region_set(C, NULL); @@ -209,8 +204,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win) if(ar->swap == WIN_FRONT_OK) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); - if(screen->subwinactive==ar->swinid) - wm_paintcursor_draw(C); + wm_paintcursor_draw(C, ar); ED_area_overdraw_flush(C, sa, ar); CTX_wm_region_set(C, NULL); @@ -257,34 +251,51 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win) } } - if(screen->do_gesture) + if(screen->do_draw_gesture) wm_gesture_draw(win); } -/******************** draw overlap ************************/ +#if 0 +/******************** draw damage ************************/ /* - not implemented */ -static void wm_method_draw_overlap(bContext *C, wmWindow *win) +static void wm_method_draw_damage(bContext *C, wmWindow *win) { wm_method_draw_all(C, win); } +#endif /****************** draw triple buffer ********************/ /* - area regions are written into a texture, without any */ /* of the overlapping menus, brushes, gestures. these */ /* are redrawn each time. */ -/* - work in progress still .. */ -/* - TODO glDeleteTextures .. */ -/* - TODO handle window resize */ -/* - TODO avoid region redraw for brush and gestures.. */ -/* - TODO use multiple smaller textures for cards without */ -/* non power of two support */ +/* */ +/* - if non-power of two textures are supported, that is */ +/* used. if not, multiple smaller ones are used, with */ +/* worst case wasted space being 23.4% for 3x3 textures */ + +#define MAX_N_TEX 3 + +typedef struct wmDrawTriple { + GLuint bind[MAX_N_TEX*MAX_N_TEX]; + int x[MAX_N_TEX], y[MAX_N_TEX]; + int nx, ny; + GLenum target; +} wmDrawTriple; static int is_pow2(int n) { return ((n)&(n-1))==0; } +static int smaller_pow2(int n) +{ + while (!is_pow2(n)) + n= n&(n-1); + + return n; +} + static int larger_pow2(int n) { if (is_pow2(n)) @@ -296,100 +307,229 @@ static int larger_pow2(int n) return n*2; } -static void wm_method_draw_triple(bContext *C, wmWindow *win) +static void split_width(int x, int n, int *splitx, int *nx) { - wmWindowManager *wm= CTX_wm_manager(C); - bScreen *screen= win->screen; - ScrArea *sa; - ARegion *ar; - float halfx, halfy, ratiox, ratioy; - int copytex= 0; + int a, newnx, waste; - if(win->drawtex) { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + /* if already power of two just use it */ + if(is_pow2(x)) { + splitx[0]= x; + (*nx)++; + return; + } - wmSubWindowSet(win, screen->mainwin); + if(n == 1) { + /* last part, we have to go larger */ + splitx[0]= larger_pow2(x); + (*nx)++; + } + else { + /* two or more parts to go, use smaller part */ + splitx[0]= smaller_pow2(x); + newnx= ++(*nx); + split_width(x-splitx[0], n-1, splitx+1, &newnx); + + for(waste=0, a=0; a<n; a++) + waste += splitx[a]; + + /* if we waste more space or use the same amount, + * revert deeper splits and just use larger */ + if(waste >= larger_pow2(x)) { + splitx[0]= larger_pow2(x); + memset(splitx+1, 0, sizeof(int)*(n-1)); + } + else + *nx= newnx; + } +} - /* wmOrtho for the screen has this same offset */ - ratiox= win->sizex/(float)win->drawtexw; - ratioy= win->sizey/(float)win->drawtexh; - halfx= 0.375f/win->drawtexw; - halfy= 0.375f/win->drawtexh; - - glBindTexture(GL_TEXTURE_2D, win->drawtex); - glEnable(GL_TEXTURE_2D); - - glColor3f(1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(0.0f, 0.0f); - glTexCoord2f(ratiox+halfx, halfy); - glVertex2f(win->sizex, 0.0f); - glTexCoord2f(ratiox+halfx, ratioy+halfy); - glVertex2f(win->sizex, win->sizey); - glTexCoord2f(halfx, ratioy+halfy); - glVertex2f(0.0f, win->sizey); - glEnd(); - - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); +static void wm_draw_triple_free(wmWindow *win) +{ + if(win->drawdata) { + wmDrawTriple *triple= win->drawdata; + + glDeleteTextures(triple->nx*triple->ny, triple->bind); + MEM_freeN(triple); + + win->drawdata= NULL; + } +} + +static void wm_draw_triple_fail(bContext *C, wmWindow *win) +{ + wm_draw_window_clear(win); + + win->drawfail= 1; + wm_method_draw_overlap_all(C, win); +} + +static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) +{ + GLint format; + int x, y; + + /* compute texture sizes */ + if(GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) { + triple->target= GL_TEXTURE_RECTANGLE_ARB; + triple->nx= 1; + triple->ny= 1; + triple->x[0]= win->sizex; + triple->y[0]= win->sizey; + } + else if(GLEW_ARB_texture_non_power_of_two) { + triple->target= GL_TEXTURE_2D; + triple->nx= 1; + triple->ny= 1; + triple->x[0]= win->sizex; + triple->y[0]= win->sizey; } else { - GLint format; + triple->target= GL_TEXTURE_2D; + triple->nx= 0; + triple->ny= 0; + split_width(win->sizex, MAX_N_TEX, triple->x, &triple->nx); + split_width(win->sizey, MAX_N_TEX, triple->y, &triple->ny); + } - glGenTextures(1, (GLuint *)&win->drawtex); + /* generate texture names */ + glGenTextures(triple->nx*triple->ny, triple->bind); - if(!win->drawtex) { - /* not the typical failure case but we handle it anyway */ - win->drawmethod= USER_DRAW_OVERLAP_ALL; - wm_method_draw_overlap_all(C, win); + if(!triple->bind[0]) { + /* not the typical failure case but we handle it anyway */ + printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n"); + return 0; + } - printf("failed to allocate texture for triple buffer drawing (generate).\n"); - return; + for(y=0; y<triple->ny; y++) { + for(x=0; x<triple->nx; x++) { + /* proxy texture is only guaranteed to test for the cases that + * there is only one texture in use, which may not be the case */ + glBindTexture(triple->target, triple->bind[x + y*triple->nx]); + glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); + + if(format != GL_RGB8) { + glBindTexture(triple->target, 0); + printf("WM: failed to allocate texture for triple buffer drawing (GL_PROXY_TEXTURE_2D).\n"); + return 0; + } + + /* setup actual texture */ + glBindTexture(triple->target, triple->bind[x + y*triple->nx]); + glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // glColor still used with this enabled? + // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(triple->target, 0); + + /* not sure if this works everywhere .. */ + if(glGetError() == GL_OUT_OF_MEMORY) { + printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n"); + return 0; + } } + } - win->drawtexw= win->sizex; - win->drawtexh= win->sizey; + return 1; +} - if(!GLEW_ARB_texture_non_power_of_two) { - win->drawtexw= larger_pow2(win->drawtexw); - win->drawtexh= larger_pow2(win->drawtexh); +static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple) +{ + float halfx, halfy, ratiox, ratioy; + int x, y, sizex, sizey, offx, offy; + + glEnable(triple->target); + + for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) { + for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) { + sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x]; + sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y]; + + /* wmOrtho for the screen has this same offset */ + ratiox= sizex; + ratioy= sizey; + halfx= 0.375f; + halfy= 0.375f; + + /* texture rectangle has unnormalized coordinates */ + if(triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x[x]; + ratioy /= triple->y[y]; + halfx /= triple->x[x]; + halfy /= triple->y[y]; + } + + glBindTexture(triple->target, triple->bind[x + y*triple->nx]); + + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(offx, offy); + + glTexCoord2f(ratiox+halfx, halfy); + glVertex2f(offx+sizex, offy); + + glTexCoord2f(ratiox+halfx, ratioy+halfy); + glVertex2f(offx+sizex, offy+sizey); + + glTexCoord2f(halfx, ratioy+halfy); + glVertex2f(offx, offy+sizey); + glEnd(); } + } - glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB8, win->drawtexw, win->drawtexh, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); + glBindTexture(triple->target, 0); + glDisable(triple->target); +} - if(format != GL_RGB8) { - /* proxy texture is only guaranteed to test for the cases that - * there is only one texture in use, which may not be the case */ - glDeleteTextures(1, (GLuint *)&win->drawtex); +static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) +{ + int x, y, sizex, sizey, offx, offy; - win->drawmethod= USER_DRAW_OVERLAP_ALL; - wm_method_draw_overlap_all(C, win); + for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) { + for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) { + sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x]; + sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y]; - printf("failed to allocate texture for triple buffer drawing (proxy test).\n"); - return; + glBindTexture(triple->target, triple->bind[x + y*triple->nx]); + glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey); } + } - glBindTexture(GL_TEXTURE_2D, win->drawtex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, win->drawtexw, win->drawtexh, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(triple->target, 0); +} - if(glGetError() == GL_OUT_OF_MEMORY) { - /* not sure if this works everywhere .. */ - glDeleteTextures(1, (GLuint *)&win->drawtex); +static void wm_method_draw_triple(bContext *C, wmWindow *win) +{ + wmWindowManager *wm= CTX_wm_manager(C); + wmDrawTriple *triple; + bScreen *screen= win->screen; + ScrArea *sa; + ARegion *ar; + int copytex= 0; + + if(win->drawdata) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + wmSubWindowSet(win, screen->mainwin); + + wm_triple_draw_textures(win, win->drawdata); - win->drawmethod= USER_DRAW_OVERLAP_ALL; - wm_method_draw_overlap_all(C, win); + triple= win->drawdata; + } + else { + win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); - printf("failed to allocate texture for triple buffer drawing (out of memory).\n"); + if(!wm_triple_gen_textures(win, win->drawdata)) { + wm_draw_triple_fail(C, win); return; } } + triple= win->drawdata; + /* draw marked area regions */ for(sa= screen->areabase.first; sa; sa= sa->next) { CTX_wm_area_set(C, sa); @@ -398,6 +538,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) if(ar->swinid && ar->do_draw) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ED_area_overdraw_flush(C, sa, ar); CTX_wm_region_set(C, NULL); copytex= 1; } @@ -410,10 +551,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) wmSubWindowSet(win, screen->mainwin); ED_area_overdraw(C); - glBindTexture(GL_TEXTURE_2D, win->drawtex); - glReadBuffer(GL_BACK); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, win->sizex, win->sizey); - glBindTexture(GL_TEXTURE_2D, 0); + wm_triple_copy_textures(win, triple); } /* after area regions so we can do area 'overlay' drawing */ @@ -428,7 +566,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) } } - if(win->screen->do_gesture) + if(win->screen->do_draw_gesture) wm_gesture_draw(win); if(wm->paintcursors.first) { @@ -440,7 +578,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) wmSubWindowSet(win, ar->swinid); ED_region_pixelspace(ar); - wm_paintcursor_draw(C); + wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); CTX_wm_area_set(C, NULL); @@ -464,7 +602,9 @@ static int wm_draw_update_test_window(wmWindow *win) return 1; if(win->screen->do_draw) return 1; - if(win->screen->do_gesture) + if(win->screen->do_draw_gesture) + return 1; + if(win->screen->do_draw_paintcursor) return 1; for(ar= win->screen->regionbase.first; ar; ar= ar->next) @@ -485,7 +625,10 @@ void wm_draw_update(bContext *C) wmWindow *win; for(win= wm->windows.first; win; win= win->next) { - win->drawmethod= USER_DRAW_OVERLAP_ALL; + if(win->drawmethod != U.wmdrawmethod) { + wm_draw_window_clear(win); + win->drawmethod= U.wmdrawmethod; + } if(wm_draw_update_test_window(win)) { CTX_wm_window_set(C, win); @@ -497,14 +640,19 @@ void wm_draw_update(bContext *C) if(win->screen->do_refresh) ED_screen_refresh(wm, win); - if(win->drawmethod == USER_DRAW_ALL) - wm_method_draw_all(C, win); - else if(win->drawmethod == USER_DRAW_OVERLAP_ALL) + if(win->drawfail) wm_method_draw_overlap_all(C, win); + else if(win->drawmethod == USER_DRAW_FULL) + wm_method_draw_full(C, win); else if(win->drawmethod == USER_DRAW_OVERLAP) - wm_method_draw_overlap(C, win); - else if(win->drawmethod == USER_DRAW_TRIPLE) + wm_method_draw_overlap_all(C, win); + /*else if(win->drawmethod == USER_DRAW_DAMAGE) + wm_method_draw_damage(C, win);*/ + else // if(win->drawmethod == USER_DRAW_TRIPLE) wm_method_draw_triple(C, win); + + win->screen->do_draw_gesture= 0; + win->screen->do_draw_paintcursor= 0; wm_window_swap_buffers(win); @@ -513,3 +661,30 @@ void wm_draw_update(bContext *C) } } +void wm_draw_window_clear(wmWindow *win) +{ + bScreen *screen= win->screen; + ScrArea *sa; + ARegion *ar; + + if(win->drawmethod == USER_DRAW_TRIPLE) + wm_draw_triple_free(win); + + /* clear screen swap flags */ + if(screen) { + for(sa= screen->areabase.first; sa; sa= sa->next) + for(ar=sa->regionbase.first; ar; ar= ar->next) + ar->swap= WIN_NONE_OK; + + screen->swap= WIN_NONE_OK; + } +} + +void wm_draw_region_clear(wmWindow *win, ARegion *ar) +{ + if(win->drawmethod == USER_DRAW_OVERLAP) + wm_flush_regions_down(win->screen, &ar->winrct); + + win->screen->do_draw= 1; +} + diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 6fc67242d69..6c0339f87b2 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -727,10 +727,17 @@ static ARegion *region_event_inside(bContext *C, int x, int y) static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar) { - if(ar) - for(; pc; pc= pc->next) - if(pc->poll(C)) - ED_region_tag_redraw(ar); + if(ar) { + for(; pc; pc= pc->next) { + if(pc->poll(C)) { + wmWindow *win= CTX_wm_window(C); + win->screen->do_draw_paintcursor= 1; + + if(win->drawmethod != USER_DRAW_TRIPLE) + ED_region_tag_redraw(ar); + } + } + } } /* called on mousemove, check updates for paintcursors */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 5847581d32a..2f4ded00de5 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -31,6 +31,7 @@ #include "DNA_screen_types.h" #include "DNA_vec_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -259,11 +260,13 @@ void wm_gesture_draw(wmWindow *win) void wm_gesture_tag_redraw(bContext *C) { + wmWindow *win= CTX_wm_window(C); bScreen *screen= CTX_wm_screen(C); ARegion *ar= CTX_wm_region(C); if(screen) - screen->do_gesture= 1; - if(ar) + screen->do_draw_gesture= 1; + if(ar && win->drawmethod != USER_DRAW_TRIPLE) ED_region_tag_redraw(ar); } + diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 58f2be80922..b9b7f83636f 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -285,13 +285,19 @@ static void recent_filelist(char *pup) static int recentfile_exec(bContext *C, wmOperator *op) { int event= RNA_enum_get(op->ptr, "nr"); - + + // XXX wm in context is not set correctly after WM_read_file -> crash + // do it before for now, but is this correct with multiple windows? + if(event>0) { - if (G.sce[0] && (event==1)) + if (G.sce[0] && (event==1)) { + WM_event_add_notifier(C, NC_WINDOW, NULL); WM_read_file(C, G.sce, op->reports); + } else { struct RecentFile *recent = BLI_findlink(&(G.recent_files), event-2); if(recent) { + WM_event_add_notifier(C, NC_WINDOW, NULL); WM_read_file(C, recent->filename, op->reports); } } @@ -347,11 +353,12 @@ static int wm_mainfile_exec(bContext *C, wmOperator *op) char filename[FILE_MAX]; RNA_string_get(op->ptr, "filename", filename); - WM_read_file(C, filename, op->reports); - // XXX wm in context is not set correctly after WM_read_file -> crash - // WM_event_add_notifier(C, NC_WINDOW, NULL); + // do it before for now, but is this correct with multiple windows? + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_read_file(C, filename, op->reports); + return 0; } diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 8431317f4d9..255d22191e2 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -231,8 +231,7 @@ void wm_subwindow_position(wmWindow *win, int swinid, rcti *winrct) static wmWindow *_curwindow= NULL; static wmSubWindow *_curswin= NULL; -/* enable the WM versions of opengl calls */ -void wmSubWindowSet(wmWindow *win, int swinid) +void wmSubWindowScissorSet(wmWindow *win, int swinid, rcti *srct) { int width, height; _curswin= swin_from_swinid(win, swinid); @@ -248,7 +247,14 @@ void wmSubWindowSet(wmWindow *win, int swinid) width= _curswin->winrct.xmax - _curswin->winrct.xmin + 1; height= _curswin->winrct.ymax - _curswin->winrct.ymin + 1; glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height); - glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height); + + if(srct) { + width= srct->xmax - srct->xmin + 1; + height= srct->ymax - srct->ymin + 1; + glScissor(srct->xmin, srct->ymin, width, height); + } + else + glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height); glMatrixMode(GL_PROJECTION); glLoadMatrixf(&_curswin->winmat[0][0]); @@ -256,7 +262,13 @@ void wmSubWindowSet(wmWindow *win, int swinid) glLoadMatrixf(&_curswin->viewmat[0][0]); glFlush(); - +} + + +/* enable the WM versions of opengl calls */ +void wmSubWindowSet(wmWindow *win, int swinid) +{ + wmSubWindowScissorSet(win, swinid, NULL); } void wmLoadMatrix(float mat[][4]) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 73860af5f85..130d72dffd8 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -49,6 +49,7 @@ #include "WM_api.h" #include "WM_types.h" #include "wm.h" +#include "wm_draw.h" #include "wm_window.h" #include "wm_subwindow.h" #include "wm_event_system.h" @@ -152,6 +153,9 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *winorig) win->screen= ED_screen_duplicate(win, winorig->screen); win->screen->do_refresh= 1; win->screen->do_draw= 1; + + win->drawmethod= -1; + win->drawdata= NULL; return win; } @@ -162,6 +166,7 @@ static void wm_window_close(bContext *C, wmWindow *win) wmWindowManager *wm= CTX_wm_manager(C); BLI_remlink(&wm->windows, win); + wm_draw_window_clear(win); WM_event_remove_handlers(C, &win->handlers); ED_screen_exit(C, win, win->screen); wm_window_free(C, win); @@ -274,6 +279,9 @@ wmWindow *WM_window_open(bContext *C, rcti *rect) win->posy= rect->ymin; win->sizex= rect->xmax - rect->xmin; win->sizey= rect->ymax - rect->ymin; + + win->drawmethod= -1; + win->drawdata= NULL; wm_window_add_ghostwindow(wm, "Blender", win); @@ -490,6 +498,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) } wm_window_make_drawable(C, win); + wm_draw_window_clear(win); WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } break; diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h new file mode 100644 index 00000000000..4b462b1b5e8 --- /dev/null +++ b/source/blender/windowmanager/wm_draw.h @@ -0,0 +1,42 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef WM_DRAW_H +#define WM_DRAW_H + +struct bContext; +struct wmWindow; +struct ARegion; + +/* wm_draw.c */ +void wm_draw_update (struct bContext *C); +void wm_draw_window_clear (struct wmWindow *win); +void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar); + +#endif /* WM_DRAW_H */ + diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 26c0b23df30..8a5806497a3 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -86,7 +86,6 @@ void wm_event_do_handlers (bContext *C); void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata); void wm_event_do_notifiers (bContext *C); -void wm_draw_update (bContext *C); /* wm_keymap.c */ |