Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import bpy
from bpy.app.handlers import persistent
TODO = True
from .preview import Preview
from .hmd import HMD
# ############################################################
# Util Functions
# ############################################################
def getAddonName():
return __name__.split('.')[0]
def getDisplayBackend(context):
"""preference set in the addon"""
addon = getAddonName()
preferences = context.user_preferences.addons[addon].preferences
return preferences.display_backend
# ############################################################
# Main Operator
# ############################################################
class VirtualRealityDisplayOperator(bpy.types.Operator):
""""""
bl_idname = "view3d.virtual_reality_display"
bl_label = "Toggle Virtual Reality Display"
bl_description = ""
_gl_data = None
_timer = None
_handle = None
_width = 1920
_height = 1080
action = bpy.props.EnumProperty(
description="",
items=(("ENABLE", "Enable", "Enable"),
("DISABLE", "Disable", "Disable"),
),
default="DISABLE",
options={'SKIP_SAVE'},
)
@classmethod
def poll(cls, context):
return context.area.type == 'VIEW_3D'
def modal(self, context, event):
wm = context.window_manager
vr = wm.virtual_reality
if not vr.is_enabled:
self._quit(context)
context.area.tag_redraw()
return {'FINISHED'}
if event.type == 'TIMER':
self.loop()
if vr.use_preview:
context.area.tag_redraw()
return {'PASS_THROUGH'}
def invoke(self, context, event):
wm = context.window_manager
vr = wm.virtual_reality
is_enabled = vr.is_enabled
if self.action == 'DISABLE':
if vr.is_enabled:
self.quit(context)
return {'FINISHED'}
else:
self.report({'ERROR'}, "Virtual Reality Display is not enabled")
return {'CANCELLED'}
else: # ENABLE
if vr.is_enabled:
self.report({'ERROR'}, "Virtual Reality Display is already enabled")
return {'CANCELLED'}
if self.init(context):
return {'RUNNING_MODAL'}
else:
# quit right away
wm.virtual_reality.is_enabled = False
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
self._quit(context)
self.report({'ERROR'}, "Error initializing device")
return {'CANCELLED'}
def quit(self, context):
"""garbage collect"""
# change it so the original modal operator will clean things up
wm = context.window_manager
wm.virtual_reality.is_enabled = False
def _quit(self, context):
"""actual quit"""
wm = context.window_manager
if self._timer:
wm.event_timer_remove(self._timer)
del self._timer
if self._handle:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
del self._handle
self._hmd.quit()
self._preview.quit()
def init(self, context):
"""
Initialize the callbacks and the external devices
"""
wm = context.window_manager
wm.virtual_reality.is_enabled = True
display_backend = getDisplayBackend(context)
self._hmd = HMD(display_backend)
self._preview = Preview()
if not self._hmd.isConnected():
return False
if not self._hmd.init():
return False
# get the data from device
width = self._hmd.width
height = self._hmd.height
texture = self._hmd.texture
self._preview.init(width, height, texture)
# setup modal
self._timer = wm.event_timer_add(1.0 / 75.0, context.window) # 75 Hz
self._handle = bpy.types.SpaceView3D.draw_handler_add(self._draw_callback_px, (context,), 'WINDOW', 'POST_PIXEL')
wm.modal_handler_add(self)
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def loop(self):
"""
Get fresh tracking data and render into the FBO
"""
self._hmd.loop()
fbo = self._hmd.fbo
width = self._hmd.width
height = self._hmd.height
projection_matrix = self._hmd.projection_matrix
modelview_matrix = self._hmd.modelview_matrix
TODO
"""
bpy.ops.view3d.offscreen(fbo, width, height, projection_matrix, modelview_matrix)
"""
self._hmd.frameReady()
def _draw_callback_px(self, context):
"""callback function, run every time the viewport is refreshed"""
self._preview.loop()
# ############################################################
# Global Properties
# ############################################################
class VirtualRealityInfo(bpy.types.PropertyGroup):
is_enabled = bpy.props.BoolProperty(
name="Enabled",
default=False,
)
use_preview = bpy.props.BoolProperty(
name="Preview",
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
)
# ############################################################
# Callbacks
# ############################################################
@persistent
def virtual_reality_load_pre(dummy):
wm = bpy.context.window_manager
wm.virtual_reality.is_enabled = False
@persistent
def virtual_reality_load_post(dummy):
wm = bpy.context.window_manager
wm.virtual_reality.is_enabled = False
# ############################################################
# Un/Registration
# ############################################################
def register():
bpy.app.handlers.load_pre.append(virtual_reality_load_pre)
bpy.app.handlers.load_pre.append(virtual_reality_load_post)
bpy.utils.register_class(VirtualRealityDisplayOperator)
bpy.utils.register_class(VirtualRealityInfo)
bpy.types.WindowManager.virtual_reality = bpy.props.PointerProperty(
name="virtual_reality",
type=VirtualRealityInfo,
options={'HIDDEN'},
)
def unregister():
bpy.app.handlers.load_pre.remove(virtual_reality_load_pre)
bpy.app.handlers.load_pre.remove(virtual_reality_load_post)
bpy.utils.unregister_class(VirtualRealityDisplayOperator)
del bpy.types.WindowManager.virtual_reality
bpy.utils.unregister_class(VirtualRealityInfo)