Blender  V3.3
wm_stereo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2015 Blender Foundation. All rights reserved. */
3 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "DNA_listBase.h"
12 
13 #include "RNA_access.h"
14 #include "RNA_prototypes.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "BLI_utildefines.h"
19 
20 #include "BKE_context.h"
21 #include "BKE_global.h"
22 #include "BKE_report.h"
23 
24 #include "GHOST_C-api.h"
25 
26 #include "ED_screen.h"
27 
28 #include "GPU_capabilities.h"
29 #include "GPU_immediate.h"
30 #include "GPU_texture.h"
31 #include "GPU_viewport.h"
32 
33 #include "WM_api.h"
34 #include "WM_types.h"
35 #include "wm.h"
36 #include "wm_draw.h"
37 #include "wm_window.h"
38 
39 #include "UI_interface.h"
40 #include "UI_resources.h"
41 
43 {
44  bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
45 
47  uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
49 
51 
52  int soffx = WM_window_pixels_x(win) * 0.5f;
53  if (view == STEREO_LEFT_ID) {
54  if (!cross_eyed) {
55  soffx = 0;
56  }
57  }
58  else { /* #RIGHT_LEFT_ID */
59  if (cross_eyed) {
60  soffx = 0;
61  }
62  }
63 
64  const int sizex = WM_window_pixels_x(win);
65  const int sizey = WM_window_pixels_y(win);
66 
67  /* wmOrtho for the screen has this same offset */
68  const float halfx = GLA_PIXEL_OFS / sizex;
69  const float halfy = GLA_PIXEL_OFS / sizex;
70 
71  /* Texture is already bound to GL_TEXTURE0 unit. */
72 
74 
75  immAttr2f(texcoord, halfx, halfy);
76  immVertex2f(pos, soffx, 0.0f);
77 
78  immAttr2f(texcoord, 1.0f + halfx, halfy);
79  immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f);
80 
81  immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
82  immVertex2f(pos, soffx + (sizex * 0.5f), sizey);
83 
84  immAttr2f(texcoord, halfx, 1.0f + halfy);
85  immVertex2f(pos, soffx, sizey);
86 
87  immEnd();
88 
90 }
91 
93 {
95  uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
97 
99 
100  int soffy;
101  if (view == STEREO_LEFT_ID) {
102  soffy = WM_window_pixels_y(win) * 0.5f;
103  }
104  else { /* STEREO_RIGHT_ID */
105  soffy = 0;
106  }
107 
108  const int sizex = WM_window_pixels_x(win);
109  const int sizey = WM_window_pixels_y(win);
110 
111  /* wmOrtho for the screen has this same offset */
112  const float halfx = GLA_PIXEL_OFS / sizex;
113  const float halfy = GLA_PIXEL_OFS / sizex;
114 
115  /* Texture is already bound to GL_TEXTURE0 unit. */
116 
118 
119  immAttr2f(texcoord, halfx, halfy);
120  immVertex2f(pos, 0.0f, soffy);
121 
122  immAttr2f(texcoord, 1.0f + halfx, halfy);
123  immVertex2f(pos, sizex, soffy);
124 
125  immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
126  immVertex2f(pos, sizex, soffy + (sizey * 0.5f));
127 
128  immAttr2f(texcoord, halfx, 1.0f + halfy);
129  immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f));
130 
131  immEnd();
132 
134 }
135 
137 {
138  return ELEM(stereo_display, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM);
139 }
140 
141 bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
142 {
143  const bScreen *screen = WM_window_get_active_screen(win);
144  const Scene *scene = WM_window_get_active_scene(win);
145 
146  /* some 3d methods change the window arrangement, thus they shouldn't
147  * toggle on/off just because there is no 3d elements being drawn */
150  }
151 
152  if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen, scene) == false)) {
153  return false;
154  }
155 
156  /* some 3d methods change the window arrangement, thus they shouldn't
157  * toggle on/off just because there is no 3d elements being drawn */
160  }
161 
162  return true;
163 }
164 
165 void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
166 {
167  if (!WM_stereo3d_enabled(win, false)) {
168  return;
169  }
170 
172  const int half_x = WM_window_pixels_x(win) / 2;
173  /* right half of the screen */
174  if (r_mouse_xy[0] > half_x) {
175  r_mouse_xy[0] -= half_x;
176  }
177  r_mouse_xy[0] *= 2;
178  }
180  const int half_y = WM_window_pixels_y(win) / 2;
181  /* upper half of the screen */
182  if (r_mouse_xy[1] > half_y) {
183  r_mouse_xy[1] -= half_y;
184  }
185  r_mouse_xy[1] *= 2;
186  }
187 }
188 
189 /************************** Stereo 3D operator **********************************/
190 typedef struct Stereo3dData {
193 
195 {
196  Stereo3dData *s3dd = op->customdata;
197  Stereo3dFormat *s3d = &s3dd->stereo3d_format;
198  PropertyRNA *prop;
199  bool is_set = false;
200 
201  prop = RNA_struct_find_property(op->ptr, "display_mode");
202  if (RNA_property_is_set(op->ptr, prop)) {
203  s3d->display_mode = RNA_property_enum_get(op->ptr, prop);
204  is_set = true;
205  }
206 
207  prop = RNA_struct_find_property(op->ptr, "anaglyph_type");
208  if (RNA_property_is_set(op->ptr, prop)) {
209  s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop);
210  is_set = true;
211  }
212 
213  prop = RNA_struct_find_property(op->ptr, "interlace_type");
214  if (RNA_property_is_set(op->ptr, prop)) {
215  s3d->interlace_type = RNA_property_enum_get(op->ptr, prop);
216  is_set = true;
217  }
218 
219  prop = RNA_struct_find_property(op->ptr, "use_interlace_swap");
220  if (RNA_property_is_set(op->ptr, prop)) {
221  if (RNA_property_boolean_get(op->ptr, prop)) {
222  s3d->flag |= S3D_INTERLACE_SWAP;
223  }
224  else {
225  s3d->flag &= ~S3D_INTERLACE_SWAP;
226  }
227  is_set = true;
228  }
229 
230  prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed");
231  if (RNA_property_is_set(op->ptr, prop)) {
232  if (RNA_property_boolean_get(op->ptr, prop)) {
234  }
235  else {
237  }
238  is_set = true;
239  }
240 
241  return is_set;
242 }
243 
245 {
246  wmWindow *win = CTX_wm_window(C);
247 
248  Stereo3dData *s3dd = MEM_callocN(sizeof(Stereo3dData), __func__);
249  op->customdata = s3dd;
250 
251  /* store the original win stereo 3d settings in case of cancel */
252  s3dd->stereo3d_format = *win->stereo3d_format;
253 }
254 
256 {
258  wmWindow *win_src = CTX_wm_window(C);
259  wmWindow *win_dst = NULL;
260  const bool is_fullscreen = WM_window_is_fullscreen(win_src);
261  char prev_display_mode = win_src->stereo3d_format->display_mode;
262  bool ok = true;
263 
264  if (G.background) {
265  return OPERATOR_CANCELLED;
266  }
267 
268  if (op->customdata == NULL) {
269  /* no invoke means we need to set the operator properties here */
270  wm_stereo3d_set_init(C, op);
272  }
273 
274  Stereo3dData *s3dd = op->customdata;
275  *win_src->stereo3d_format = s3dd->stereo3d_format;
276 
277  if (prev_display_mode == S3D_DISPLAY_PAGEFLIP &&
278  prev_display_mode != win_src->stereo3d_format->display_mode) {
279  /* in case the hardware supports pageflip but not the display */
280  if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
281  /* pass */
282  }
283  else {
284  BKE_report(
285  op->reports,
286  RPT_ERROR,
287  "Failed to create a window without quad-buffer support, you may experience flickering");
288  ok = false;
289  }
290  }
291  else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
292  const bScreen *screen = WM_window_get_active_screen(win_src);
293 
294  /* ED_workspace_layout_duplicate() can't handle other cases yet T44688 */
295  if (screen->state != SCREENNORMAL) {
296  BKE_report(
297  op->reports, RPT_ERROR, "Failed to switch to Time Sequential mode when in fullscreen");
298  ok = false;
299  }
300  /* pageflip requires a new window to be created with the proper OS flags */
301  else if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
303  BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
304  }
305  else {
306  wm_window_close(C, wm, win_dst);
307  win_dst = NULL;
308  BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system");
309  ok = false;
310  }
311  }
312  else {
313  BKE_report(op->reports,
314  RPT_ERROR,
315  "Failed to create a window compatible with the time sequential display method");
316  ok = false;
317  }
318  }
319 
321  if (!is_fullscreen) {
322  BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen");
323  }
324  }
325 
326  MEM_freeN(op->customdata);
327 
328  if (ok) {
329  if (win_dst) {
330  wm_window_close(C, wm, win_src);
331  }
332 
334  return OPERATOR_FINISHED;
335  }
336 
337  /* Without this, the popup won't be freed properly, see T44688. */
338  CTX_wm_window_set(C, win_src);
339  win_src->stereo3d_format->display_mode = prev_display_mode;
340  return OPERATOR_CANCELLED;
341 }
342 
344 {
345  wm_stereo3d_set_init(C, op);
346 
347  if (wm_stereo3d_set_properties(C, op)) {
348  return wm_stereo3d_set_exec(C, op);
349  }
350  return WM_operator_props_dialog_popup(C, op, 300);
351 }
352 
354 {
355  Stereo3dData *s3dd = op->customdata;
356  PointerRNA stereo3d_format_ptr;
357  uiLayout *layout = op->layout;
358  uiLayout *col;
359 
360  RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, &s3dd->stereo3d_format, &stereo3d_format_ptr);
361 
362  uiLayoutSetPropSep(layout, true);
363  uiLayoutSetPropDecorate(layout, false);
364 
365  col = uiLayoutColumn(layout, false);
366  uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
367 
368  switch (s3dd->stereo3d_format.display_mode) {
369  case S3D_DISPLAY_ANAGLYPH: {
370  uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
371  break;
372  }
373  case S3D_DISPLAY_INTERLACE: {
374  uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
375  uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
376  break;
377  }
378  case S3D_DISPLAY_SIDEBYSIDE: {
379  uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
380  /* fall-through */
381  }
384  default: {
385  break;
386  }
387  }
388 }
389 
391 {
392  /* the check function guarantees that the menu is updated to show the
393  * sub-options when an enum change (e.g., it shows the anaglyph options
394  * when anaglyph is on, and the interlace options when this is on */
395  return true;
396 }
397 
399 {
400  MEM_freeN(op->customdata);
401  op->customdata = NULL;
402 }
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:966
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
unsigned int uint
Definition: BLI_sys_types.h:67
#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:133
bool GPU_stereo_quadbuffer_support(void)
void immUnbindProgram(void)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
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:25
@ GPU_SHADER_2D_IMAGE
Definition: GPU_shader.h:216
@ 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.
#define C
Definition: RandGen.cpp:25
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:325
Scene scene
uint pos
uint col
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
Stereo3dFormat stereo3d_format
Definition: wm_stereo.c:191
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
struct Stereo3dFormat * stereo3d_format
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:42
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
Definition: wm_stereo.c:141
static bool wm_stereo3d_set_properties(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:194
void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
Definition: wm_stereo.c:92
struct Stereo3dData Stereo3dData
static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
Definition: wm_stereo.c:136
int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
Definition: wm_stereo.c:255
bool wm_stereo3d_set_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
Definition: wm_stereo.c:390
static void wm_stereo3d_set_init(bContext *C, wmOperator *op)
Definition: wm_stereo.c:244
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_stereo.c:343
void wm_stereo3d_set_draw(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:353
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
Definition: wm_stereo.c:165
void wm_stereo3d_set_cancel(bContext *UNUSED(C), wmOperator *op)
Definition: wm_stereo.c:398
int WM_window_pixels_y(const wmWindow *win)
Definition: wm_window.c:2082
bool WM_window_is_fullscreen(const wmWindow *win)
Definition: wm_window.c:2126
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:366
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2300
int WM_window_pixels_x(const wmWindow *win)
Definition: wm_window.c:2076
wmWindow * wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
Definition: wm_window.c:297
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2183