Blender  V2.93
wm_stereo.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2015 by Blender Foundation
17  * All rights reserved.
18  */
19 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "DNA_listBase.h"
28 
29 #include "RNA_access.h"
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_utildefines.h"
34 
35 #include "BKE_context.h"
36 #include "BKE_global.h"
37 #include "BKE_report.h"
38 
39 #include "GHOST_C-api.h"
40 
41 #include "ED_screen.h"
42 
43 #include "GPU_capabilities.h"
44 #include "GPU_immediate.h"
45 #include "GPU_texture.h"
46 #include "GPU_viewport.h"
47 
48 #include "WM_api.h"
49 #include "WM_types.h"
50 #include "wm.h"
51 #include "wm_draw.h"
52 #include "wm_window.h"
53 
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56 
58 {
59  bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
60 
62  uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
64 
66 
67  int soffx = WM_window_pixels_x(win) * 0.5f;
68  if (view == STEREO_LEFT_ID) {
69  if (!cross_eyed) {
70  soffx = 0;
71  }
72  }
73  else { /* #RIGHT_LEFT_ID */
74  if (cross_eyed) {
75  soffx = 0;
76  }
77  }
78 
79  const int sizex = WM_window_pixels_x(win);
80  const int sizey = WM_window_pixels_y(win);
81 
82  /* wmOrtho for the screen has this same offset */
83  const float halfx = GLA_PIXEL_OFS / sizex;
84  const float halfy = GLA_PIXEL_OFS / sizex;
85 
86  immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
87 
89 
90  immAttr2f(texcoord, halfx, halfy);
91  immVertex2f(pos, soffx, 0.0f);
92 
93  immAttr2f(texcoord, 1.0f + halfx, halfy);
94  immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f);
95 
96  immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
97  immVertex2f(pos, soffx + (sizex * 0.5f), sizey);
98 
99  immAttr2f(texcoord, halfx, 1.0f + halfy);
100  immVertex2f(pos, soffx, sizey);
101 
102  immEnd();
103 
105 }
106 
108 {
110  uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
112 
114 
115  int soffy;
116  if (view == STEREO_LEFT_ID) {
117  soffy = WM_window_pixels_y(win) * 0.5f;
118  }
119  else { /* STEREO_RIGHT_ID */
120  soffy = 0;
121  }
122 
123  const int sizex = WM_window_pixels_x(win);
124  const int sizey = WM_window_pixels_y(win);
125 
126  /* wmOrtho for the screen has this same offset */
127  const float halfx = GLA_PIXEL_OFS / sizex;
128  const float halfy = GLA_PIXEL_OFS / sizex;
129 
130  immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
131 
133 
134  immAttr2f(texcoord, halfx, halfy);
135  immVertex2f(pos, 0.0f, soffy);
136 
137  immAttr2f(texcoord, 1.0f + halfx, halfy);
138  immVertex2f(pos, sizex, soffy);
139 
140  immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
141  immVertex2f(pos, sizex, soffy + (sizey * 0.5f));
142 
143  immAttr2f(texcoord, halfx, 1.0f + halfy);
144  immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f));
145 
146  immEnd();
147 
149 }
150 
152 {
153  return ELEM(stereo_display, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM);
154 }
155 
156 bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
157 {
158  const bScreen *screen = WM_window_get_active_screen(win);
159  const Scene *scene = WM_window_get_active_scene(win);
160 
161  /* some 3d methods change the window arrangement, thus they shouldn't
162  * toggle on/off just because there is no 3d elements being drawn */
165  }
166 
167  if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen, scene) == false)) {
168  return false;
169  }
170 
171  /* some 3d methods change the window arrangement, thus they shouldn't
172  * toggle on/off just because there is no 3d elements being drawn */
175  }
176 
177  return true;
178 }
179 
184 void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
185 {
186  if (!WM_stereo3d_enabled(win, false)) {
187  return;
188  }
189 
191  const int half_x = WM_window_pixels_x(win) / 2;
192  /* right half of the screen */
193  if (r_mouse_xy[0] > half_x) {
194  r_mouse_xy[0] -= half_x;
195  }
196  r_mouse_xy[0] *= 2;
197  }
199  const int half_y = WM_window_pixels_y(win) / 2;
200  /* upper half of the screen */
201  if (r_mouse_xy[1] > half_y) {
202  r_mouse_xy[1] -= half_y;
203  }
204  r_mouse_xy[1] *= 2;
205  }
206 }
207 
208 /************************** Stereo 3D operator **********************************/
209 typedef struct Stereo3dData {
212 
214 {
215  Stereo3dData *s3dd = op->customdata;
216  Stereo3dFormat *s3d = &s3dd->stereo3d_format;
217  PropertyRNA *prop;
218  bool is_set = false;
219 
220  prop = RNA_struct_find_property(op->ptr, "display_mode");
221  if (RNA_property_is_set(op->ptr, prop)) {
222  s3d->display_mode = RNA_property_enum_get(op->ptr, prop);
223  is_set = true;
224  }
225 
226  prop = RNA_struct_find_property(op->ptr, "anaglyph_type");
227  if (RNA_property_is_set(op->ptr, prop)) {
228  s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop);
229  is_set = true;
230  }
231 
232  prop = RNA_struct_find_property(op->ptr, "interlace_type");
233  if (RNA_property_is_set(op->ptr, prop)) {
234  s3d->interlace_type = RNA_property_enum_get(op->ptr, prop);
235  is_set = true;
236  }
237 
238  prop = RNA_struct_find_property(op->ptr, "use_interlace_swap");
239  if (RNA_property_is_set(op->ptr, prop)) {
240  if (RNA_property_boolean_get(op->ptr, prop)) {
241  s3d->flag |= S3D_INTERLACE_SWAP;
242  }
243  else {
244  s3d->flag &= ~S3D_INTERLACE_SWAP;
245  }
246  is_set = true;
247  }
248 
249  prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed");
250  if (RNA_property_is_set(op->ptr, prop)) {
251  if (RNA_property_boolean_get(op->ptr, prop)) {
253  }
254  else {
256  }
257  is_set = true;
258  }
259 
260  return is_set;
261 }
262 
264 {
265  wmWindow *win = CTX_wm_window(C);
266 
267  Stereo3dData *s3dd = MEM_callocN(sizeof(Stereo3dData), __func__);
268  op->customdata = s3dd;
269 
270  /* store the original win stereo 3d settings in case of cancel */
271  s3dd->stereo3d_format = *win->stereo3d_format;
272 }
273 
275 {
277  wmWindow *win_src = CTX_wm_window(C);
278  wmWindow *win_dst = NULL;
279  const bool is_fullscreen = WM_window_is_fullscreen(win_src);
280  char prev_display_mode = win_src->stereo3d_format->display_mode;
281  bool ok = true;
282 
283  if (G.background) {
284  return OPERATOR_CANCELLED;
285  }
286 
287  if (op->customdata == NULL) {
288  /* no invoke means we need to set the operator properties here */
289  wm_stereo3d_set_init(C, op);
291  }
292 
293  Stereo3dData *s3dd = op->customdata;
294  *win_src->stereo3d_format = s3dd->stereo3d_format;
295 
296  if (prev_display_mode == S3D_DISPLAY_PAGEFLIP &&
297  prev_display_mode != win_src->stereo3d_format->display_mode) {
298  /* in case the hardware supports pageflip but not the display */
299  if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
300  /* pass */
301  }
302  else {
303  BKE_report(
304  op->reports,
305  RPT_ERROR,
306  "Failed to create a window without quad-buffer support, you may experience flickering");
307  ok = false;
308  }
309  }
310  else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
311  const bScreen *screen = WM_window_get_active_screen(win_src);
312 
313  /* ED_workspace_layout_duplicate() can't handle other cases yet T44688 */
314  if (screen->state != SCREENNORMAL) {
315  BKE_report(
316  op->reports, RPT_ERROR, "Failed to switch to Time Sequential mode when in fullscreen");
317  ok = false;
318  }
319  /* pageflip requires a new window to be created with the proper OS flags */
320  else if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
322  BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
323  }
324  else {
325  wm_window_close(C, wm, win_dst);
326  win_dst = NULL;
327  BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system");
328  ok = false;
329  }
330  }
331  else {
332  BKE_report(op->reports,
333  RPT_ERROR,
334  "Failed to create a window compatible with the time sequential display method");
335  ok = false;
336  }
337  }
338 
340  if (!is_fullscreen) {
341  BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen");
342  }
343  }
344 
345  MEM_freeN(op->customdata);
346 
347  if (ok) {
348  if (win_dst) {
349  wm_window_close(C, wm, win_src);
350  }
351 
353  return OPERATOR_FINISHED;
354  }
355 
356  /* without this, the popup won't be freed freed properly T44688 */
357  CTX_wm_window_set(C, win_src);
358  win_src->stereo3d_format->display_mode = prev_display_mode;
359  return OPERATOR_CANCELLED;
360 }
361 
363 {
364  wm_stereo3d_set_init(C, op);
365 
366  if (wm_stereo3d_set_properties(C, op)) {
367  return wm_stereo3d_set_exec(C, op);
368  }
369  return WM_operator_props_dialog_popup(C, op, 300);
370 }
371 
373 {
374  Stereo3dData *s3dd = op->customdata;
375  PointerRNA stereo3d_format_ptr;
376  uiLayout *layout = op->layout;
377  uiLayout *col;
378 
379  RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, &s3dd->stereo3d_format, &stereo3d_format_ptr);
380 
381  uiLayoutSetPropSep(layout, true);
382  uiLayoutSetPropDecorate(layout, false);
383 
384  col = uiLayoutColumn(layout, false);
385  uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
386 
387  switch (s3dd->stereo3d_format.display_mode) {
388  case S3D_DISPLAY_ANAGLYPH: {
389  uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
390  break;
391  }
392  case S3D_DISPLAY_INTERLACE: {
393  uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
394  uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
395  break;
396  }
397  case S3D_DISPLAY_SIDEBYSIDE: {
398  uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
399  /* fall-through */
400  }
403  default: {
404  break;
405  }
406  }
407 }
408 
410 {
411  /* the check function guarantees that the menu is updated to show the
412  * sub-options when an enum change (e.g., it shows the anaglyph options
413  * when anaglyph is on, and the interlace options when this is on */
414  return true;
415 }
416 
418 {
419  MEM_freeN(op->customdata);
420  op->customdata = NULL;
421 }
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:942
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define ELEM(...)
These structs are the foundation for all linked lists in the library system.
@ S3D_INTERLACE_SWAP
@ S3D_SIDEBYSIDE_CROSSEYED
eStereoDisplayMode
@ S3D_DISPLAY_ANAGLYPH
@ S3D_DISPLAY_INTERLACE
@ S3D_DISPLAY_TOPBOTTOM
@ S3D_DISPLAY_SIDEBYSIDE
@ S3D_DISPLAY_PAGEFLIP
@ STEREO_LEFT_ID
@ SCREENNORMAL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene)
static AppView * view
GHOST C-API function and type declarations.
GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle)
@ GHOST_kWindowStateFullScreen
Definition: GHOST_Types.h:148
bool GPU_stereo_quadbuffer_support(void)
void immUnbindProgram(void)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
GPUVertFormat * immVertexFormat(void)
void immAttr2f(uint attr_id, float x, float y)
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
@ GPU_PRIM_TRI_FAN
Definition: GPU_primitive.h:41
@ GPU_SHADER_2D_IMAGE
Definition: GPU_shader.h:186
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
StructRNA RNA_Stereo3dDisplay
#define C
Definition: RandGen.cpp:39
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
#define NC_WINDOW
Definition: WM_types.h:277
Scene scene
uint pos
uint col
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2331
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
Stereo3dFormat stereo3d_format
Definition: wm_stereo.c:210
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
struct Stereo3dFormat * stereo3d_format
#define G(x, y, z)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width)
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view)
Definition: wm_stereo.c:57
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
Definition: wm_stereo.c:156
static bool wm_stereo3d_set_properties(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:213
void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
Definition: wm_stereo.c:107
struct Stereo3dData Stereo3dData
static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
Definition: wm_stereo.c:151
int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
Definition: wm_stereo.c:274
bool wm_stereo3d_set_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
Definition: wm_stereo.c:409
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
Definition: wm_stereo.c:184
static void wm_stereo3d_set_init(bContext *C, wmOperator *op)
Definition: wm_stereo.c:263
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_stereo.c:362
void wm_stereo3d_set_draw(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:372
void wm_stereo3d_set_cancel(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:417
int WM_window_pixels_y(const wmWindow *win)
Definition: wm_window.c:2136
bool WM_window_is_fullscreen(const wmWindow *win)
Definition: wm_window.c:2187
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:389
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2372
int WM_window_pixels_x(const wmWindow *win)
Definition: wm_window.c:2130
wmWindow * wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
Definition: wm_window.c:313
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2249