diff options
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 17 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_draw.c | 284 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 140 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_keymap.c | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 54 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_stereo.c | 534 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 105 | ||||
-rw-r--r-- | source/blender/windowmanager/wm.h | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_draw.h | 21 |
13 files changed, 1035 insertions, 139 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index df5826338c0..75df966887c 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC intern/wm_operators.c intern/wm_subwindow.c intern/wm_window.c + intern/wm_stereo.c intern/wm_widgets.c intern/wm_generic_widgets.c 3d_widgets/arrow_widget.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 0ccc3888b5e..83aacefb247 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -111,6 +111,7 @@ void WM_window_open_temp (struct bContext *C, struct rcti *position, int type); /* returns true if draw method is triple buffer */ bool WM_is_draw_triple(struct wmWindow *win); +bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); /* files */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 455375a0fec..91767a990d4 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -180,9 +180,11 @@ enum { #define KM_NOTHING 0 #define KM_PRESS 1 #define KM_RELEASE 2 -#define KM_CLICK 3 -#define KM_DBL_CLICK 4 +/* clicktype */ +#define KM_CLICK 3 /* clicked key (click_time <= U.click_timeout) */ +#define KM_DBL_CLICK 4 /* double click - keep at 4 to avoid breakage with older key configs */ +#define KM_HOLD 5 /* held key (click_time > U.click_timeout) */ /* ************** UI Handler ***************** */ @@ -427,7 +429,9 @@ typedef struct wmEvent { short type; /* event code itself (short, is also in keymap) */ short val; /* press, release, scrollvalue */ + short click_type; /* click, hold or double click */ int x, y; /* mouse pointer position, screen coord */ + double click_time; /* the time since keypress started */ int mval[2]; /* region mouse position, name convention pre 2.5 :) */ char utf8_buf[6]; /* from, ghost if utf8 is enabled for the platform, * BLI_str_utf8_size() must _always_ be valid, check @@ -435,20 +439,19 @@ typedef struct wmEvent { char ascii; /* from ghost, fallback if utf8 isn't set */ char pad; - /* previous state, used for double click and the 'click' */ + bool is_key_pressed; /* is a (non-modifier) key is pressed? (keyboard, mouse, NDOF, ...) */ + + /* previous state, used for clicktype */ short prevtype; short prevval; int prevx, prevy; - double prevclicktime; + double prevclick_time; int prevclickx, prevclicky; /* modifier states */ short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */ short keymodifier; /* rawkey modifier */ - /* set in case a KM_PRESS went by unhandled */ - short check_click; - /* keymap item, set by handler (weak?) */ const char *keymap_idname; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 7440570f4a0..16fe9ca5142 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -48,9 +48,11 @@ #include "BIF_gl.h" #include "BKE_context.h" +#include "BKE_image.h" #include "GHOST_C-api.h" +#include "ED_node.h" #include "ED_view3d.h" #include "ED_screen.h" @@ -165,6 +167,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win) if (ar->swinid) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); } @@ -175,12 +178,14 @@ static void wm_method_draw_full(bContext *C, wmWindow *win) } ED_screen_draw(win); + win->screen->do_draw = false; /* draw overlapping regions */ for (ar = screen->regionbase.first; ar; ar = ar->next) { if (ar->swinid) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -278,6 +283,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->do_draw) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); @@ -288,6 +294,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->swap == WIN_FRONT_OK) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); @@ -300,7 +307,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) } } } - + wm_area_mark_invalid_backbuf(sa); CTX_wm_area_set(C, NULL); } @@ -308,6 +315,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) /* after area regions so we can do area 'overlay' drawing */ if (screen->do_draw) { ED_screen_draw(win); + win->screen->do_draw = false; if (exchange) screen->swap = WIN_FRONT_OK; @@ -315,6 +323,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) else if (exchange) { if (screen->swap == WIN_FRONT_OK) { ED_screen_draw(win); + win->screen->do_draw = false; screen->swap = WIN_BOTH_OK; } else if (screen->swap == WIN_BACK_OK) @@ -328,6 +337,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->swinid && ar->do_draw) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -360,15 +370,6 @@ static void wm_method_draw_damage(bContext *C, wmWindow *win) /* 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 void split_width(int x, int n, int *splitx, int *nx) { int a, newnx, waste; @@ -405,16 +406,13 @@ static void split_width(int x, int n, int *splitx, int *nx) } } -static void wm_draw_triple_free(wmWindow *win) +static void wm_draw_triple_free(wmDrawTriple *triple) { - if (win->drawdata) { - wmDrawTriple *triple = win->drawdata; + if (triple) { glDeleteTextures(triple->nx * triple->ny, triple->bind); MEM_freeN(triple); - - win->drawdata = NULL; } } @@ -499,7 +497,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) return 1; } -static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) +void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) { const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); @@ -571,7 +569,7 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) glBindTexture(triple->target, 0); } -static void wm_draw_region_blend(wmWindow *win, ARegion *ar) +static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple) { float fac = ED_region_blend_factor(ar); @@ -580,7 +578,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar) wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true); glEnable(GL_BLEND); - wm_triple_draw_textures(win, win->drawdata, 1.0f - fac); + wm_triple_draw_textures(win, triple, 1.0f - fac); glDisable(GL_BLEND); } } @@ -589,29 +587,46 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) { wmWindowManager *wm = CTX_wm_manager(C); wmDrawTriple *triple; + wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first; bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = 0; + int copytex = false; - if (win->drawdata) { + if (drawdata && drawdata->triple) { 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, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); } else { - win->drawdata = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); + /* we run it when we start OR when we turn stereo on */ + if (drawdata == NULL) { + drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData"); + BLI_addhead(&win->drawdata, drawdata); + } + + drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); - if (!wm_triple_gen_textures(win, win->drawdata)) { + if (!wm_triple_gen_textures(win, drawdata->triple)) { wm_draw_triple_fail(C, win); return; } } - triple = win->drawdata; + /* it means stereo was just turned off */ + /* note: we are removing all drawdatas that are not the first */ + for (dd = drawdata->next; dd; dd = dd_next) { + dd_next = dd->next; + + BLI_remlink(&win->drawdata, dd); + wm_draw_triple_free(dd->triple); + MEM_freeN(dd); + } + + triple = drawdata->triple; /* draw marked area regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -619,16 +634,17 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->do_draw) { - - if (ar->overlap == 0) { + + if (ar->overlap == false) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_region_set(C, NULL); - copytex = 1; + copytex = true; } } } - + wm_area_mark_invalid_backbuf(sa); CTX_wm_area_set(C, NULL); } @@ -662,14 +678,15 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* draw overlapping area regions (always like popups) */ for (sa = screen->areabase.first; sa; sa = sa->next) { CTX_wm_area_set(C, sa); - + for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->overlap) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_region_set(C, NULL); - - wm_draw_region_blend(win, ar); + + wm_draw_region_blend(win, ar, triple); } } @@ -678,12 +695,14 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* after area regions so we can do area 'overlay' drawing */ ED_screen_draw(win); + win->screen->do_draw = false; /* draw floating regions (menus) */ for (ar = screen->regionbase.first; ar; ar = ar->next) { if (ar->swinid) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -691,13 +710,188 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* always draw, not only when screen tagged */ if (win->gesture.first) wm_gesture_draw(win); - + /* needs pixel coords in screen */ if (wm->drags.first) { wm_drags_draw(C, win, NULL); } } +static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoViews sview) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmDrawData *drawdata; + wmDrawTriple *triple_data, *triple_all; + bScreen *screen = win->screen; + ScrArea *sa; + ARegion *ar; + int copytex = false; + int id; + + /* we store the triple_data in sequence to triple_all */ + for (id = 0; id < 2; id++) { + drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id); + + if (drawdata && drawdata->triple) { + if (id == 0) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + wmSubWindowSet(win, screen->mainwin); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + } + } + else { + /* we run it when we start OR when we turn stereo on */ + if (drawdata == NULL) { + drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData"); + BLI_addtail(&win->drawdata, drawdata); + } + + drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); + + if (!wm_triple_gen_textures(win, drawdata->triple)) { + wm_draw_triple_fail(C, win); + return; + } + } + } + + triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple; + triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple; + + /* draw marked area regions */ + for (sa = screen->areabase.first; sa; sa = sa->next) { + CTX_wm_area_set(C, sa); + + switch (sa->spacetype) { + case SPACE_IMAGE: + { + SpaceImage *sima = sa->spacedata.first; + sima->iuser.multiview_eye = sview; + break; + } + case SPACE_VIEW3D: + { + View3D *v3d = sa->spacedata.first; + BGpic *bgpic = v3d->bgpicbase.first; + v3d->multiview_eye = sview; + if (bgpic) bgpic->iuser.multiview_eye = sview; + break; + } + case SPACE_NODE: + { + SpaceNode *snode = sa->spacedata.first; + if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) { + Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ima->eye = sview; + } + break; + } + case SPACE_SEQ: + { + SpaceSeq *sseq = sa->spacedata.first; + sseq->multiview_eye = sview; + break; + } + } + + /* draw marked area regions */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->do_draw) { + + if (ar->overlap == false) { + CTX_wm_region_set(C, ar); + ED_region_do_draw(C, ar); + + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + + CTX_wm_region_set(C, NULL); + copytex = true; + } + } + } + + wm_area_mark_invalid_backbuf(sa); + CTX_wm_area_set(C, NULL); + } + + if (copytex) { + wmSubWindowSet(win, screen->mainwin); + + wm_triple_copy_textures(win, triple_data); + } + + if (wm->paintcursors.first) { + for (sa = screen->areabase.first; sa; sa = sa->next) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->swinid == screen->subwinactive) { + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* make region ready for draw, scissor, pixelspace */ + ED_region_set(C, ar); + wm_paintcursor_draw(C, ar); + + CTX_wm_region_set(C, NULL); + CTX_wm_area_set(C, NULL); + } + } + } + + wmSubWindowSet(win, screen->mainwin); + } + + /* draw overlapping area regions (always like popups) */ + for (sa = screen->areabase.first; sa; sa = sa->next) { + CTX_wm_area_set(C, sa); + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->overlap) { + CTX_wm_region_set(C, ar); + ED_region_do_draw(C, ar); + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + CTX_wm_region_set(C, NULL); + + wm_draw_region_blend(win, ar, triple_data); + } + } + + CTX_wm_area_set(C, NULL); + } + + /* after area regions so we can do area 'overlay' drawing */ + ED_screen_draw(win); + if (sview == STEREO_RIGHT_ID) + win->screen->do_draw = false; + + /* draw floating regions (menus) */ + for (ar = screen->regionbase.first; ar; ar = ar->next) { + if (ar->swinid) { + CTX_wm_menu_set(C, ar); + ED_region_do_draw(C, ar); + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + CTX_wm_menu_set(C, NULL); + } + } + + /* always draw, not only when screen tagged */ + if (win->gesture.first) + wm_gesture_draw(win); + + /* needs pixel coords in screen */ + if (wm->drags.first) { + wm_drags_draw(C, win, NULL); + } + + /* copy the ui + overlays */ + wmSubWindowSet(win, screen->mainwin); + wm_triple_copy_textures(win, triple_all); +} /****************** main update call **********************/ @@ -848,8 +1042,16 @@ void wm_draw_update(bContext *C) wm_method_draw_overlap_all(C, win, 0); else if (drawmethod == USER_DRAW_OVERLAP_FLIP) wm_method_draw_overlap_all(C, win, 1); - else // if (drawmethod == USER_DRAW_TRIPLE) - wm_method_draw_triple(C, win); + else { /* USER_DRAW_TRIPLE */ + if ((WM_stereo3d_enabled(win, false)) == false) { + wm_method_draw_triple(C, win); + } + else { + wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID); + wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID); + wm_method_draw_stereo3d(C, win); + } + } win->screen->do_draw_gesture = false; win->screen->do_draw_paintcursor = false; @@ -862,15 +1064,23 @@ void wm_draw_update(bContext *C) } } +void wm_draw_data_free(wmWindow *win) +{ + wmDrawData *dd; + + for (dd = win->drawdata.first; dd; dd = dd->next) { + wm_draw_triple_free(dd->triple); + } + BLI_freelistN(&win->drawdata); +} + void wm_draw_window_clear(wmWindow *win) { bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int drawmethod = wm_automatic_draw_method(win); - if (drawmethod == USER_DRAW_TRIPLE) - wm_draw_triple_free(win); + wm_draw_data_free(win); /* clear screen swap flags */ if (screen) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 59c35ff541f..c5252e28690 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -404,7 +404,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve * to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */ if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) && (event->type != LEFTMOUSE) && - (event->val == KM_DBL_CLICK)) + (event->click_type == KM_DBL_CLICK)) { return WM_HANDLER_CONTINUE; } @@ -1476,6 +1476,7 @@ int WM_userdef_event_map(int kmitype) } +/* XXX rename to something more descriptive like wm_event_is_keymapitem_matching and use bool */ static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi) { int kmitype = WM_userdef_event_map(kmi->type); @@ -1492,10 +1493,13 @@ static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi) if (kmitype != KM_ANY) if (winevent->type != kmitype) return 0; - + + /* KM_ANY excludes KM_HOLD since it's time based and not a real input - filter it out */ + if (kmi->val == KM_ANY && winevent->click_type == KM_HOLD) return 0; + if (kmi->val != KM_ANY) - if (winevent->val != kmi->val) return 0; - + if (!ELEM(kmi->val, winevent->val, winevent->click_type)) return 0; + /* modifiers also check bits, so it allows modifier order */ if (kmi->shift != KM_ANY) if (winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0; @@ -1542,8 +1546,9 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve /* modal keymap checking returns handled events fine, but all hardcoded modal * handling typically swallows all events (OPERATOR_RUNNING_MODAL). * This bypass just disables support for double clicks in hardcoded modal handlers */ - if (event->val == KM_DBL_CLICK) { + if (event->click_type == KM_DBL_CLICK) { event->val = KM_PRESS; + event->click_type = 0; *dbl_click_disabled = true; } } @@ -1575,9 +1580,9 @@ static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled) event->val = event->prevval; event->prevval = 0; } - else if (dbl_click_disabled) - event->val = KM_DBL_CLICK; - + else if (dbl_click_disabled) { + event->click_type = KM_DBL_CLICK; + } } /* Warning: this function removes a modal handler, when finished */ @@ -2120,47 +2125,21 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) /* test for CLICK events */ if (wm_action_not_handled(action)) { wmWindow *win = CTX_wm_window(C); - - /* eventstate stores if previous event was a KM_PRESS, in case that - * wasn't handled, the KM_RELEASE will become a KM_CLICK */ - - if (win && event->val == KM_PRESS) { - win->eventstate->check_click = true; - } - - if (win && win->eventstate->prevtype == event->type) { - - if ((event->val == KM_RELEASE) && - (win->eventstate->prevval == KM_PRESS) && - (win->eventstate->check_click == true)) - { - event->val = KM_CLICK; - - if (G.debug & (G_DEBUG_HANDLERS)) { - printf("%s: handling CLICK\n", __func__); - } - - action |= wm_handlers_do_intern(C, event, handlers); - event->val = KM_RELEASE; - } - else if (event->val == KM_DBL_CLICK) { + /* XXX check if those double click hacks can be removed/improved since click_type was introduced */ + if (win && win->eventstate->prevtype == event->type) { + if (event->click_type == KM_DBL_CLICK) { event->val = KM_PRESS; + event->click_type = 0; action |= wm_handlers_do_intern(C, event, handlers); /* revert value if not handled */ if (wm_action_not_handled(action)) { - event->val = KM_DBL_CLICK; + event->click_type = KM_DBL_CLICK; } } } } - else { - wmWindow *win = CTX_wm_window(C); - - if (win) - win->eventstate->check_click = 0; - } } return action; @@ -3104,22 +3083,50 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi return NULL; } -static bool wm_event_is_double_click(wmEvent *event, wmEvent *event_state) +/** + * Clicktype test + * + * We have 3 different click_types: #KM_CLICK, #KM_HOLD# and #KM_DBL_CLICK. + * + * Time is used to determine, what to send. It works as follows: + * - #KM_RELEASE && time since first #KM_PRESS < U.click_timeout --> send #KM_CLICK + * - #KM_PRESS && time since first #KM_PRESS > U.click_timeout --> send #KM_HOLD + * - #KM_PRESS after a #KM_RELEASE && time since previous #KM_PRESS < U.dbl_click_time --> send #KM_DBL_CLICK + * + * \note: only #KM_DBL_CLICK is handled here, rest in #wm_window_event_clicktype_init (wm_window.c) + */ +static void wm_event_clicktype_init(wmWindow *win, wmEvent *event, wmEvent *event_state) { - if ((event->type == event_state->prevtype) && - (event_state->prevval == KM_RELEASE) && - (event->val == KM_PRESS)) + short click_type = 0; + + if ((event->val == KM_PRESS) && + (event_state->prevval != KM_PRESS || event->prevtype != win->eventstate->prevtype)) + { + event_state->prevclick_time = event->click_time; + event_state->prevclickx = event->x; + event_state->prevclicky = event->y; + } + + /* double click */ + if (event->type == event_state->prevtype && + event_state->prevval == KM_RELEASE && + event->val == KM_PRESS) { if ((ISMOUSE(event->type) == false) || ((ABS(event->x - event_state->prevclickx)) <= 2 && (ABS(event->y - event_state->prevclicky)) <= 2)) { - if ((PIL_check_seconds_timer() - event_state->prevclicktime) * 1000 < U.dbl_click_time) { - return true; + if ((PIL_check_seconds_timer() - event_state->prevclick_time) * 1000 < U.dbl_click_time) { + click_type = KM_DBL_CLICK; + if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS)) { + printf("%s Send double click event\n", __func__); + } } } } - return false; + if (click_type != event->click_type) { + event_state->click_type = event->click_type = click_type; + } } static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event) @@ -3208,7 +3215,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.x = evt->x = pd->x; event.y = evt->y = pd->y; - event.val = 0; + event.val = KM_NOTHING; /* Use prevx/prevy so we can calculate the delta later */ event.prevx = event.x - pd->deltaX; @@ -3251,6 +3258,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U evt->val = event.val; evt->type = event.type; + /* click_type */ + wm_event_clicktype_init(win, &event, evt); + if (win->active == 0) { int cx, cy; @@ -3261,18 +3271,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.y = evt->y = cy; } - /* double click test */ - if (wm_event_is_double_click(&event, evt)) { - if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS)) - printf("%s Send double click\n", __func__); - event.val = KM_DBL_CLICK; - } - if (event.val == KM_PRESS) { - evt->prevclicktime = PIL_check_seconds_timer(); - evt->prevclickx = event.x; - evt->prevclicky = event.y; - } - /* add to other window if event is there (not to both!) */ owin = wm_event_cursor_other_windows(wm, win, &event); if (owin) { @@ -3311,7 +3309,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U /* copy to event state */ evt->val = event.val; evt->type = event.type; - + + /* clicktype */ + wm_event_clicktype_init(win, &event, evt); + /* exclude arrow keys, esc, etc from text input */ if (type == GHOST_kEventKeyUp) { event.ascii = '\0'; @@ -3377,14 +3378,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.keymodifier = evt->keymodifier = 0; break; } - - /* double click test */ - /* if previous event was same type, and previous was release, and now it presses... */ - if (wm_event_is_double_click(&event, evt)) { - if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS)) - printf("%s Send double click\n", __func__); - evt->val = event.val = KM_DBL_CLICK; - } /* this case happens on holding a key pressed, it should not generate * press events events with the same key as modifier */ @@ -3405,13 +3398,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U G.is_break = true; } - /* double click test - only for press */ - if (event.val == KM_PRESS) { - evt->prevclicktime = PIL_check_seconds_timer(); - evt->prevclickx = event.x; - evt->prevclicky = event.y; - } - wm_event_add(win, &event); break; @@ -3436,7 +3422,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.type = TIMER; event.custom = EVT_DATA_TIMER; event.customdata = customdata; - event.val = 0; + event.val = KM_NOTHING; event.keymodifier = 0; wm_event_add(win, &event); @@ -3446,7 +3432,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U case GHOST_kEventNDOFMotion: { event.type = NDOF_MOTION; - event.val = 0; + event.val = KM_NOTHING; attach_ndof_data(&event, customdata); wm_event_add(win, &event); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 3fd1fe427c9..f3e9c416e7b 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -846,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, err_out); + IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out); } else { ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, false, R_ALPHAPREMUL, err_out); + IB_rect, false, R_ALPHAPREMUL, NULL, err_out); } if (ibuf) { diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index b1bb45686fc..8edccbce25d 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -60,7 +60,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" -#include "BKE_mball.h" +#include "BKE_mball_tessellate.h" #include "BKE_node.h" #include "BKE_report.h" diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 82e46c1b333..0a89ca113c4 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1192,11 +1192,15 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2) return 0; if (k1->val != KM_ANY && k2->val != KM_ANY) { + +#if 0 /* thanks to clicktype those shouldn't be needed anymore */ /* take click, press, release conflict into account */ if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; +#endif + if (k1->val != k2->val) return 0; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a0749e01e38..c325afce2b6 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -172,6 +172,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); /* Set the default i18n context now, so that opfunc can redefine it if needed! */ RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT); + ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot); if (ot->name == NULL) { @@ -194,6 +195,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); /* Set the default i18n context now, so that opfunc can redefine it if needed! */ RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT); + ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); RNA_def_struct_identifier(ot->srna, ot->idname); @@ -374,6 +376,7 @@ static void wm_macro_cancel(bContext *C, wmOperator *op) wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag) { wmOperatorType *ot; + const char *i18n_context; if (WM_operatortype_find(idname, true)) { printf("%s: macro error: operator %s exists\n", __func__, idname); @@ -400,8 +403,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); RNA_def_struct_identifier(ot->srna, ot->idname); /* Use i18n context from ext.srna if possible (py operators). */ - RNA_def_struct_translation_context(ot->srna, ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : - BLF_I18NCONTEXT_OPERATOR_DEFAULT); + i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLF_I18NCONTEXT_OPERATOR_DEFAULT; + RNA_def_struct_translation_context(ot->srna, i18n_context); + ot->translation_context = i18n_context; BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); @@ -427,6 +431,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), /* Set the default i18n context now, so that opfunc can redefine it if needed! */ RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT); + ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); @@ -1263,6 +1268,13 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, if (flag & WM_FILESEL_RELPATH) RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file"); + if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) { + prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + } + prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -4617,8 +4629,10 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) for (a = 0; a < iter; a++) { if (type == 0) { - if (ar) + if (ar) { ED_region_do_draw(C, ar); + ar->do_draw = false; + } } else if (type == 1) { wmWindow *win = CTX_wm_window(C); @@ -4646,6 +4660,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) if (ar_iter->swinid) { CTX_wm_region_set(C, ar_iter); ED_region_do_draw(C, ar_iter); + ar->do_draw = false; } } } @@ -4857,6 +4872,36 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot) } /* ******************************************************* */ +/* toggle 3D for current window, turning it fullscreen if needed */ +static void WM_OT_stereo3d_set(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Set Stereo 3D"; + ot->idname = "WM_OT_set_stereo_3d"; + ot->description = "Toggle 3D stereo support for current window (or change the display mode)"; + + ot->exec = wm_stereo3d_set_exec; + ot->invoke = wm_stereo3d_set_invoke; + ot->poll = WM_operator_winactive; + ot->ui = wm_stereo3d_set_draw; + ot->cancel = wm_stereo3d_set_cancel; + + prop = RNA_def_enum(ot->srna, "display_mode", stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "anaglyph_type", stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "interlace_type", stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_interlace_swap", false, "Swap Left/Right", + "Swap left and right stereo channels"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_sidebyside_crosseyed", false, "Cross-Eyed", + "Right eye should see left image and vice-versa"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/* ******************************************************* */ /* called on initialize WM_exit() */ void wm_operatortype_free(void) { @@ -4899,6 +4944,7 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_call_menu_pie); WM_operatortype_append(WM_OT_radial_control); WM_operatortype_append(WM_OT_widget_tweak); + WM_operatortype_append(WM_OT_stereo3d_set); #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); #endif @@ -5134,7 +5180,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0); /* menus that can be accessed anywhere in blender */ - WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_CLICK, 0, 0); WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0); /* Space switching */ diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c new file mode 100644 index 00000000000..5d7b11272c6 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -0,0 +1,534 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 by Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_stereo.c + * \ingroup wm + */ + + +#include <stdlib.h> +#include <string.h> + +#include "DNA_listBase.h" + +#include "RNA_access.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_utildefines.h" + +#include "BIF_gl.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_report.h" + +#include "GHOST_C-api.h" + +#include "ED_screen.h" + +#include "GPU_glew.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" +#include "wm_draw.h" /* wmDrawTriple */ +#include "wm_window.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +static void wm_method_draw_stereo3d_pageflip(wmWindow *win) +{ + wmDrawData *drawdata; + int view; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + if (view == STEREO_LEFT_ID) + glDrawBuffer(GL_BACK_LEFT); + else //STEREO_RIGHT_ID + glDrawBuffer(GL_BACK_RIGHT); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + } +} + +static GLuint left_interlace_mask[32]; +static GLuint right_interlace_mask[32]; +static enum eStereo3dInterlaceType interlace_prev_type = -1; +static char interlace_prev_swap = -1; + +static void wm_interlace_masks_create(wmWindow *win) +{ + GLuint pattern; + char i; + bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0; + enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type; + + if (interlace_prev_type == interlace_type && interlace_prev_swap == swap) + return; + + switch (interlace_type) { + case S3D_INTERLACE_ROW: + pattern = 0x00000000; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i += 2) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + for (i = 1; i < 32; i += 2) { + left_interlace_mask[i] = ~pattern; + right_interlace_mask[i] = pattern; + } + break; + case S3D_INTERLACE_COLUMN: + pattern = 0x55555555; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i++) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + break; + case S3D_INTERLACE_CHECKERBOARD: + default: + pattern = 0x55555555; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i += 2) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + for (i = 1; i < 32; i += 2) { + left_interlace_mask[i] = ~pattern; + right_interlace_mask[i] = pattern; + } + break; + } + interlace_prev_type = interlace_type; + interlace_prev_swap = swap; +} + +static void wm_method_draw_stereo3d_interlace(wmWindow *win) +{ + wmDrawData *drawdata; + int view; + + wm_interlace_masks_create(win); + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(view ? (GLubyte *) right_interlace_mask : (GLubyte *) left_interlace_mask); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + glDisable(GL_POLYGON_STIPPLE); + } +} + +static void wm_method_draw_stereo3d_anaglyph(wmWindow *win) +{ + wmDrawData *drawdata; + int view, bit; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + bit = view + 1; + switch (win->stereo3d_format->anaglyph_type) { + case S3D_ANAGLYPH_REDCYAN: + glColorMask((1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + case S3D_ANAGLYPH_GREENMAGENTA: + glColorMask((2&bit) ? GL_TRUE : GL_FALSE, + (1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + case S3D_ANAGLYPH_YELLOWBLUE: + glColorMask((1&bit) ? GL_TRUE : GL_FALSE, + (1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + } + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) +{ + wmDrawData *drawdata; + wmDrawTriple *triple; + float halfx, halfy, ratiox, ratioy; + int x, y, offx, offy; + float alpha = 1.0f; + int view; + int soffx; + bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + triple = drawdata->triple; + + soffx = WM_window_pixels_x(win) * 0.5f; + if (view == STEREO_LEFT_ID) { + if (!cross_eyed) + soffx = 0; + } + else { //RIGHT_LEFT_ID + if (cross_eyed) + soffx = 0; + } + + 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++) { + const int sizex = triple->x[x]; + const int sizey = triple->y[y]; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* 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]); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(soffx + (offx * 0.5f), offy); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(soffx + ((offx + sizex) * 0.5f), offy); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(soffx + (offx * 0.5f), offy + sizey); + glEnd(); + } + } + + glBindTexture(triple->target, 0); + glDisable(triple->target); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +static void wm_method_draw_stereo3d_topbottom(wmWindow *win) +{ + wmDrawData *drawdata; + wmDrawTriple *triple; + float halfx, halfy, ratiox, ratioy; + int x, y, offx, offy; + float alpha = 1.0f; + int view; + int soffy; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + triple = drawdata->triple; + + if (view == STEREO_LEFT_ID) { + soffy = WM_window_pixels_y(win) * 0.5f; + } + else { /* STEREO_RIGHT_ID */ + soffy = 0; + } + + 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++) { + const int sizex = triple->x[x]; + const int sizey = triple->y[y]; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* 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]); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(offx, soffy + (offy * 0.5f)); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(offx + sizex, soffy + (offy * 0.5f)); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f)); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(offx, soffy + ((offy + sizey) * 0.5f)); + glEnd(); + } + } + + glBindTexture(triple->target, 0); + glDisable(triple->target); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win) +{ + switch (win->stereo3d_format->display_mode) { + case S3D_DISPLAY_ANAGLYPH: + wm_method_draw_stereo3d_anaglyph(win); + break; + case S3D_DISPLAY_INTERLACE: + wm_method_draw_stereo3d_interlace(win); + break; + case S3D_DISPLAY_PAGEFLIP: + wm_method_draw_stereo3d_pageflip(win); + break; + case S3D_DISPLAY_SIDEBYSIDE: + wm_method_draw_stereo3d_sidebyside(win); + break; + case S3D_DISPLAY_TOPBOTTOM: + wm_method_draw_stereo3d_topbottom(win); + break; + default: + break; + } +} + +static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display) +{ + return ELEM(stereo_display, + S3D_DISPLAY_SIDEBYSIDE, + S3D_DISPLAY_TOPBOTTOM, + S3D_DISPLAY_PAGEFLIP); +} + +bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check) +{ + bScreen *screen = win->screen; + + if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) + return false; + + if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) + return WM_window_is_fullscreen(win); + + return true; +} + +/************************** Stereo 3D operator **********************************/ +typedef struct Stereo3dData { + Stereo3dFormat stereo3d_format; +} Stereo3dData; + +static bool wm_stereo3d_set_properties(bContext *C, wmOperator *op) +{ + wmWindow *win = CTX_wm_window(C); + Stereo3dFormat *s3d = win->stereo3d_format; + PropertyRNA *prop; + bool is_set = false; + + prop = RNA_struct_find_property(op->ptr, "display_mode"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->display_mode = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "anaglyph_type"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "interlace_type"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->interlace_type = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "use_interlace_swap"); + if (RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) + s3d->flag |= S3D_INTERLACE_SWAP; + else + s3d->flag &= ~S3D_INTERLACE_SWAP; + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed"); + if (RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) + s3d->flag |= S3D_SIDEBYSIDE_CROSSEYED; + else + s3d->flag &= ~S3D_SIDEBYSIDE_CROSSEYED; + is_set = true; + } + + return is_set; +} + +static void wm_stereo3d_set_init(bContext *C, wmOperator *op) +{ + Stereo3dData *s3dd; + wmWindow *win = CTX_wm_window(C); + + op->customdata = s3dd = MEM_callocN(sizeof(Stereo3dData), __func__); + + /* store the original win stereo 3d settings in case of cancel */ + s3dd->stereo3d_format = *win->stereo3d_format; +} + +int wm_stereo3d_set_exec(bContext *C, wmOperator *op) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + const bool is_fullscreen = WM_window_is_fullscreen(win); + + if (G.background) + return OPERATOR_CANCELLED; + + /* pagelfip requires a new window to be created with the proper OS flags */ + if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) { + if (wm_window_duplicate_exec(C, op) == OPERATOR_FINISHED) { + wm_window_close(C, wm, win); + win = wm->windows.last; + } + else { + BKE_reportf(op->reports, RPT_ERROR, + "Fail to create a window compatible with time sequential (page-flip) display method"); + return OPERATOR_CANCELLED; + } + } + + if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) { + if (!is_fullscreen) { + wm_window_fullscreen_toggle_exec(C, op); + } + } + + if (op->customdata) { + MEM_freeN(op->customdata); + } + + WM_event_add_notifier(C, NC_WINDOW, NULL); + return OPERATOR_FINISHED; +} + +int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wm_stereo3d_set_init(C, op); + + if (wm_stereo3d_set_properties(C, op)) + return wm_stereo3d_set_exec(C, op); + else + return WM_operator_props_dialog_popup(C, op, 250, 100); +} + +void wm_stereo3d_set_draw(bContext *C, wmOperator *op) +{ + wmWindow *win = CTX_wm_window(C); + Stereo3dFormat *stereo3d_format; + PointerRNA stereo3d_format_ptr; + uiLayout *layout = op->layout; + uiLayout *col; + + stereo3d_format = win->stereo3d_format; + RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, stereo3d_format, &stereo3d_format_ptr); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE); + + switch (stereo3d_format->display_mode) { + case S3D_DISPLAY_ANAGLYPH: + { + uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE); + break; + } + case S3D_DISPLAY_INTERLACE: + { + uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE); + uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE); + break; + } + case S3D_DISPLAY_SIDEBYSIDE: + { + uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE); + /* fall-through */ + } + case S3D_DISPLAY_PAGEFLIP: + case S3D_DISPLAY_TOPBOTTOM: + default: + { + break; + } + } +} + +void wm_stereo3d_set_cancel(bContext *C, wmOperator *op) +{ + Stereo3dData *s3dd = op->customdata; + wmWindow *win = CTX_wm_window(C); + + /* roll back to the original */ + if (win) { + *win->stereo3d_format = s3dd->stereo3d_format; + } + + MEM_freeN(op->customdata); + op->customdata = NULL; +} diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 4f7e5ab75b3..61bddb144ae 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -206,12 +206,13 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) wm_event_free_all(win); wm_subwindows_free(win); - - if (win->drawdata) - MEM_freeN(win->drawdata); - + + wm_draw_data_free(win); + wm_ghostwindow_destroy(win); - + + MEM_freeN(win->stereo3d_format); + MEM_freeN(win); } @@ -236,6 +237,8 @@ wmWindow *wm_window_new(bContext *C) BLI_addtail(&wm->windows, win); win->winid = find_free_winid(wm); + win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"); + return win; } @@ -259,8 +262,11 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *winorig) win->screen->do_draw = true; win->drawmethod = U.wmdrawmethod; - win->drawdata = NULL; - + + BLI_listbase_clear(&win->drawdata); + + *win->stereo3d_format = *winorig->stereo3d_format; + return win; } @@ -367,6 +373,10 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm glSettings.numOfAASamples = multisamples; + /* a new window is created when pageflip mode is required for a window */ + if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) + glSettings.flags |= GHOST_glStereoVisual; + if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT)) glSettings.flags |= GHOST_glWarnSupport; @@ -519,8 +529,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) win->sizey = BLI_rcti_size_y(rect); win->drawmethod = U.wmdrawmethod; - win->drawdata = NULL; - + WM_check(C); return win; @@ -1097,6 +1106,76 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr return 1; } +/** + * #KM_DBL_CLICK is set in wm_event_clicktype_init (wm_event_system.c) + * Normally, this should be there too, but for #KM_CLICK/#KM_HOLD, we need a + * time precision of a few milliseconds, which we can't get from there + */ +static void wm_window_event_clicktype_init(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + if (wm->winactive) { + wmWindow *win = wm->winactive; + wmEvent *event = win->eventstate; + short click_type = event->click_type; + + BLI_assert(event != NULL); + + if ((event->type == EVENT_NONE) || + ((event->val == KM_NOTHING) && (event->is_key_pressed == false))) + { + /* nothing needs to be done here */ + return; + } + + /* we always want click_type of last clicked button (to enable + * use with modifier keys) - unnecessary for mouse though */ + if (!ISMOUSE(event->type) && + event->val == KM_PRESS && + event->type != event->keymodifier) + { + event->is_key_pressed = false; + } + else if (event->val == KM_PRESS && !event->is_key_pressed) { + event->is_key_pressed = true; + event->click_time = PIL_check_seconds_timer(); + } + else if (event->val == KM_RELEASE && event->is_key_pressed) { + event->is_key_pressed = false; + } + else if (event->is_key_pressed == false) { + return; + } + + /* the actual test */ + if ((PIL_check_seconds_timer() - event->click_time) * 1000 <= U.click_timeout) { + /* for any reason some X11 systems send two release events triggering two KM_CLICK + * events - making the rules more strict by checking for prevval resolves this */ + if (event->val == KM_RELEASE && event->prevval != KM_RELEASE) { + click_type = KM_CLICK; + if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS)) { + printf("%s Send click event\n", __func__); + } + } + } + else if (event->is_key_pressed) { + click_type = KM_HOLD; + if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS)) { + printf("%s Send hold event\n", __func__); + } + + /* the event we send in this case is a "dummy" event - don't send value */ + event->val = KM_NOTHING; + } + + /* send event with new click_type */ + if (event->click_type != click_type) { + event->click_type = click_type; + wm_event_add(win, event); + } + } +} /* This timer system only gives maximum 1 timer event per redraw cycle, * to prevent queues to get overloaded. @@ -1132,7 +1211,7 @@ static int wm_window_timer(const bContext *C) wm_event_init_from_window(win, &event); event.type = wt->event_type; - event.val = 0; + event.val = KM_NOTHING; event.keymodifier = 0; event.custom = EVT_DATA_TIMER; event.customdata = wt; @@ -1156,7 +1235,11 @@ void wm_window_process_events(const bContext *C) if (hasevent) GHOST_DispatchEvents(g_system); - + + /* not nice to have this here, but it's the only place + * that can call it with the needed time precision */ + wm_window_event_clicktype_init(C); + hasevent |= wm_window_timer(C); /* no event, we sleep 5 milliseconds */ diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 811d5ca6921..42581bd8517 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -153,6 +153,13 @@ void wm_autosave_delete(void); void wm_autosave_read(bContext *C, struct ReportList *reports); void wm_autosave_location(char *filepath); +/* wm_stereo.c */ +void wm_method_draw_stereo3d(const bContext *C, wmWindow *win); +int wm_stereo3d_set_exec(bContext *C, wmOperator *op); +int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event); +void wm_stereo3d_set_draw(bContext *C, wmOperator *op); +void wm_stereo3d_set_cancel(bContext *C, wmOperator *op); + /* init operator properties */ void wm_open_init_load_ui(wmOperator *op, bool use_prefs); void wm_open_init_use_scripts(wmOperator *op, bool use_prefs); diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index 3d72fe17c79..5dc52b2e4fb 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -32,6 +32,23 @@ #ifndef __WM_DRAW_H__ #define __WM_DRAW_H__ +#include "GPU_glew.h" + + +#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; + +typedef struct wmDrawData { + struct wmDrawData *next, *prev; + wmDrawTriple *triple; +} wmDrawData; + struct bContext; struct wmWindow; struct ARegion; @@ -43,5 +60,9 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar); void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar); +void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha); + +void wm_draw_data_free (struct wmWindow *win); + #endif /* __WM_DRAW_H__ */ |