Cleanup: quiet float argument to in type warning
[blender-addons.git] / viewport_vr_preview / operators.py
blob2b75da28cc2ca545461810dfa334a5fc7e02b5eb
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 if "bpy" in locals():
4 import importlib
5 importlib.reload(properties)
6 else:
7 from . import properties
9 import bpy
10 import gpu
11 from bpy.app.translations import pgettext_data as data_
12 from bpy.types import (
13 Gizmo,
14 GizmoGroup,
15 Operator,
17 import math
18 from math import radians
19 from mathutils import Euler, Matrix, Quaternion, Vector
22 ### Landmarks.
23 class VIEW3D_OT_vr_landmark_add(Operator):
24 bl_idname = "view3d.vr_landmark_add"
25 bl_label = "Add VR Landmark"
26 bl_description = "Add a new VR landmark to the list and select it"
27 bl_options = {'UNDO', 'REGISTER'}
29 def execute(self, context):
30 scene = context.scene
31 landmarks = scene.vr_landmarks
33 landmarks.add()
35 # select newly created set
36 scene.vr_landmarks_selected = len(landmarks) - 1
38 return {'FINISHED'}
41 class VIEW3D_OT_vr_landmark_from_camera(Operator):
42 bl_idname = "view3d.vr_landmark_from_camera"
43 bl_label = "Add VR Landmark from Camera"
44 bl_description = "Add a new VR landmark from the active camera object to the list and select it"
45 bl_options = {'UNDO', 'REGISTER'}
47 @classmethod
48 def poll(cls, context):
49 cam_selected = False
51 vl_objects = bpy.context.view_layer.objects
52 if vl_objects.active and vl_objects.active.type == 'CAMERA':
53 cam_selected = True
54 return cam_selected
56 def execute(self, context):
57 scene = context.scene
58 landmarks = scene.vr_landmarks
59 cam = context.view_layer.objects.active
60 lm = landmarks.add()
61 lm.type = 'OBJECT'
62 lm.base_pose_object = cam
63 lm.name = "LM_" + cam.name
65 # select newly created set
66 scene.vr_landmarks_selected = len(landmarks) - 1
68 return {'FINISHED'}
71 class VIEW3D_OT_vr_landmark_from_session(Operator):
72 bl_idname = "view3d.vr_landmark_from_session"
73 bl_label = "Add VR Landmark from Session"
74 bl_description = "Add VR landmark from the viewer pose of the running VR session to the list and select it"
75 bl_options = {'UNDO', 'REGISTER'}
77 @classmethod
78 def poll(cls, context):
79 return bpy.types.XrSessionState.is_running(context)
81 def execute(self, context):
82 scene = context.scene
83 landmarks = scene.vr_landmarks
84 wm = context.window_manager
86 lm = landmarks.add()
87 lm.type = "CUSTOM"
88 scene.vr_landmarks_selected = len(landmarks) - 1
90 loc = wm.xr_session_state.viewer_pose_location
91 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
93 lm.base_pose_location = loc
94 lm.base_pose_angle = rot[2]
96 return {'FINISHED'}
99 class VIEW3D_OT_vr_camera_landmark_from_session(Operator):
100 bl_idname = "view3d.vr_camera_landmark_from_session"
101 bl_label = "Add Camera and VR Landmark from Session"
102 bl_description = "Create a new Camera and VR Landmark from the viewer pose of the running VR session and select it"
103 bl_options = {'UNDO', 'REGISTER'}
105 @classmethod
106 def poll(cls, context):
107 return bpy.types.XrSessionState.is_running(context)
109 def execute(self, context):
110 scene = context.scene
111 landmarks = scene.vr_landmarks
112 wm = context.window_manager
114 lm = landmarks.add()
115 lm.type = 'OBJECT'
116 scene.vr_landmarks_selected = len(landmarks) - 1
118 loc = wm.xr_session_state.viewer_pose_location
119 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
121 cam = bpy.data.cameras.new(data_("Camera") + "_" + lm.name)
122 new_cam = bpy.data.objects.new(data_("Camera") + "_" + lm.name, cam)
123 scene.collection.objects.link(new_cam)
124 new_cam.location = loc
125 new_cam.rotation_euler = rot
127 lm.base_pose_object = new_cam
129 return {'FINISHED'}
132 class VIEW3D_OT_update_vr_landmark(Operator):
133 bl_idname = "view3d.update_vr_landmark"
134 bl_label = "Update Custom VR Landmark"
135 bl_description = "Update the selected landmark from the current viewer pose in the VR session"
136 bl_options = {'UNDO', 'REGISTER'}
138 @classmethod
139 def poll(cls, context):
140 selected_landmark = properties.VRLandmark.get_selected_landmark(context)
141 return bpy.types.XrSessionState.is_running(context) and selected_landmark.type == 'CUSTOM'
143 def execute(self, context):
144 wm = context.window_manager
146 lm = properties.VRLandmark.get_selected_landmark(context)
148 loc = wm.xr_session_state.viewer_pose_location
149 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
151 lm.base_pose_location = loc
152 lm.base_pose_angle = rot
154 # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
155 properties.vr_landmark_active_update(None, context)
157 return {'FINISHED'}
160 class VIEW3D_OT_vr_landmark_remove(Operator):
161 bl_idname = "view3d.vr_landmark_remove"
162 bl_label = "Remove VR Landmark"
163 bl_description = "Delete the selected VR landmark from the list"
164 bl_options = {'UNDO', 'REGISTER'}
166 def execute(self, context):
167 scene = context.scene
168 landmarks = scene.vr_landmarks
170 if len(landmarks) > 1:
171 landmark_selected_idx = scene.vr_landmarks_selected
172 landmarks.remove(landmark_selected_idx)
174 scene.vr_landmarks_selected -= 1
176 return {'FINISHED'}
179 class VIEW3D_OT_cursor_to_vr_landmark(Operator):
180 bl_idname = "view3d.cursor_to_vr_landmark"
181 bl_label = "Cursor to VR Landmark"
182 bl_description = "Move the 3D Cursor to the selected VR Landmark"
183 bl_options = {'UNDO', 'REGISTER'}
185 @classmethod
186 def poll(cls, context):
187 lm = properties.VRLandmark.get_selected_landmark(context)
188 if lm.type == 'SCENE_CAMERA':
189 return context.scene.camera is not None
190 elif lm.type == 'OBJECT':
191 return lm.base_pose_object is not None
193 return True
195 def execute(self, context):
196 scene = context.scene
197 lm = properties.VRLandmark.get_selected_landmark(context)
198 if lm.type == 'SCENE_CAMERA':
199 lm_pos = scene.camera.location
200 elif lm.type == 'OBJECT':
201 lm_pos = lm.base_pose_object.location
202 else:
203 lm_pos = lm.base_pose_location
204 scene.cursor.location = lm_pos
206 return{'FINISHED'}
209 class VIEW3D_OT_add_camera_from_vr_landmark(Operator):
210 bl_idname = "view3d.add_camera_from_vr_landmark"
211 bl_label = "New Camera from VR Landmark"
212 bl_description = "Create a new Camera from the selected VR Landmark"
213 bl_options = {'UNDO', 'REGISTER'}
215 def execute(self, context):
216 scene = context.scene
217 lm = properties.VRLandmark.get_selected_landmark(context)
219 cam = bpy.data.cameras.new(data_("Camera") + "_" + lm.name)
220 new_cam = bpy.data.objects.new(data_("Camera") + "_" + lm.name, cam)
221 scene.collection.objects.link(new_cam)
222 angle = lm.base_pose_angle
223 new_cam.location = lm.base_pose_location
224 new_cam.rotation_euler = (math.pi / 2, 0, angle)
226 return {'FINISHED'}
229 class VIEW3D_OT_camera_to_vr_landmark(Operator):
230 bl_idname = "view3d.camera_to_vr_landmark"
231 bl_label = "Scene Camera to VR Landmark"
232 bl_description = "Position the scene camera at the selected landmark"
233 bl_options = {'UNDO', 'REGISTER'}
235 @classmethod
236 def poll(cls, context):
237 return context.scene.camera is not None
239 def execute(self, context):
240 scene = context.scene
241 lm = properties.VRLandmark.get_selected_landmark(context)
243 cam = scene.camera
244 angle = lm.base_pose_angle
245 cam.location = lm.base_pose_location
246 cam.rotation_euler = (math.pi / 2, 0, angle)
248 return {'FINISHED'}
251 class VIEW3D_OT_vr_landmark_activate(Operator):
252 bl_idname = "view3d.vr_landmark_activate"
253 bl_label = "Activate VR Landmark"
254 bl_description = "Change to the selected VR landmark from the list"
255 bl_options = {'UNDO', 'REGISTER'}
257 index: bpy.props.IntProperty(
258 name="Index",
259 options={'HIDDEN'},
262 def execute(self, context):
263 scene = context.scene
265 if self.index >= len(scene.vr_landmarks):
266 return {'CANCELLED'}
268 scene.vr_landmarks_active = (
269 self.index if self.properties.is_property_set(
270 "index") else scene.vr_landmarks_selected
273 return {'FINISHED'}
276 ### Gizmos.
277 class VIEW3D_GT_vr_camera_cone(Gizmo):
278 bl_idname = "VIEW_3D_GT_vr_camera_cone"
280 aspect = 1.0, 1.0
282 def draw(self, context):
283 if not hasattr(self, "frame_shape"):
284 aspect = self.aspect
286 frame_shape_verts = (
287 (-aspect[0], -aspect[1], -1.0),
288 (aspect[0], -aspect[1], -1.0),
289 (aspect[0], aspect[1], -1.0),
290 (-aspect[0], aspect[1], -1.0),
292 lines_shape_verts = (
293 (0.0, 0.0, 0.0),
294 frame_shape_verts[0],
295 (0.0, 0.0, 0.0),
296 frame_shape_verts[1],
297 (0.0, 0.0, 0.0),
298 frame_shape_verts[2],
299 (0.0, 0.0, 0.0),
300 frame_shape_verts[3],
303 self.frame_shape = self.new_custom_shape(
304 'LINE_LOOP', frame_shape_verts)
305 self.lines_shape = self.new_custom_shape(
306 'LINES', lines_shape_verts)
308 # Ensure correct GL state (otherwise other gizmos might mess that up)
309 gpu.state.line_width_set(1.0)
310 gpu.state.blend_set('ALPHA')
312 self.draw_custom_shape(self.frame_shape)
313 self.draw_custom_shape(self.lines_shape)
316 class VIEW3D_GT_vr_controller_grip(Gizmo):
317 bl_idname = "VIEW_3D_GT_vr_controller_grip"
319 def draw(self, context):
320 gpu.state.line_width_set(1.0)
321 gpu.state.blend_set('ALPHA')
323 self.color = 0.422, 0.438, 0.446
324 self.draw_preset_circle(self.matrix_basis, axis='POS_X')
325 self.draw_preset_circle(self.matrix_basis, axis='POS_Y')
326 self.draw_preset_circle(self.matrix_basis, axis='POS_Z')
329 class VIEW3D_GT_vr_controller_aim(Gizmo):
330 bl_idname = "VIEW_3D_GT_vr_controller_aim"
332 def draw(self, context):
333 gpu.state.line_width_set(1.0)
334 gpu.state.blend_set('ALPHA')
336 self.color = 1.0, 0.2, 0.322
337 self.draw_preset_arrow(self.matrix_basis, axis='POS_X')
338 self.color = 0.545, 0.863, 0.0
339 self.draw_preset_arrow(self.matrix_basis, axis='POS_Y')
340 self.color = 0.157, 0.565, 1.0
341 self.draw_preset_arrow(self.matrix_basis, axis='POS_Z')
344 class VIEW3D_GGT_vr_viewer_pose(GizmoGroup):
345 bl_idname = "VIEW3D_GGT_vr_viewer_pose"
346 bl_label = "VR Viewer Pose Indicator"
347 bl_space_type = 'VIEW_3D'
348 bl_region_type = 'WINDOW'
349 bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
351 @classmethod
352 def poll(cls, context):
353 view3d = context.space_data
354 return (
355 view3d.shading.vr_show_virtual_camera and
356 bpy.types.XrSessionState.is_running(context) and
357 not view3d.mirror_xr_session
360 @staticmethod
361 def _get_viewer_pose_matrix(context):
362 wm = context.window_manager
364 loc = wm.xr_session_state.viewer_pose_location
365 rot = wm.xr_session_state.viewer_pose_rotation
367 rotmat = Matrix.Identity(3)
368 rotmat.rotate(rot)
369 rotmat.resize_4x4()
370 transmat = Matrix.Translation(loc)
372 return transmat @ rotmat
374 def setup(self, context):
375 gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
376 gizmo.aspect = 1 / 3, 1 / 4
378 gizmo.color = gizmo.color_highlight = 0.2, 0.6, 1.0
379 gizmo.alpha = 1.0
381 self.gizmo = gizmo
383 def draw_prepare(self, context):
384 self.gizmo.matrix_basis = self._get_viewer_pose_matrix(context)
387 class VIEW3D_GGT_vr_controller_poses(GizmoGroup):
388 bl_idname = "VIEW3D_GGT_vr_controller_poses"
389 bl_label = "VR Controller Poses Indicator"
390 bl_space_type = 'VIEW_3D'
391 bl_region_type = 'WINDOW'
392 bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
394 @classmethod
395 def poll(cls, context):
396 view3d = context.space_data
397 return (
398 view3d.shading.vr_show_controllers and
399 bpy.types.XrSessionState.is_running(context) and
400 not view3d.mirror_xr_session
403 @staticmethod
404 def _get_controller_pose_matrix(context, idx, is_grip, scale):
405 wm = context.window_manager
407 loc = None
408 rot = None
409 if is_grip:
410 loc = wm.xr_session_state.controller_grip_location_get(context, idx)
411 rot = wm.xr_session_state.controller_grip_rotation_get(context, idx)
412 else:
413 loc = wm.xr_session_state.controller_aim_location_get(context, idx)
414 rot = wm.xr_session_state.controller_aim_rotation_get(context, idx)
416 rotmat = Matrix.Identity(3)
417 rotmat.rotate(Quaternion(Vector(rot)))
418 rotmat.resize_4x4()
419 transmat = Matrix.Translation(loc)
420 scalemat = Matrix.Scale(scale, 4)
422 return transmat @ rotmat @ scalemat
424 def setup(self, context):
425 for idx in range(2):
426 self.gizmos.new(VIEW3D_GT_vr_controller_grip.bl_idname)
427 self.gizmos.new(VIEW3D_GT_vr_controller_aim.bl_idname)
429 for gizmo in self.gizmos:
430 gizmo.aspect = 1 / 3, 1 / 4
431 gizmo.color_highlight = 1.0, 1.0, 1.0
432 gizmo.alpha = 1.0
434 def draw_prepare(self, context):
435 grip_idx = 0
436 aim_idx = 0
437 idx = 0
438 scale = 1.0
439 for gizmo in self.gizmos:
440 is_grip = (gizmo.bl_idname == VIEW3D_GT_vr_controller_grip.bl_idname)
441 if (is_grip):
442 idx = grip_idx
443 grip_idx += 1
444 scale = 0.1
445 else:
446 idx = aim_idx
447 aim_idx += 1
448 scale = 0.5
449 gizmo.matrix_basis = self._get_controller_pose_matrix(context, idx, is_grip, scale)
452 class VIEW3D_GGT_vr_landmarks(GizmoGroup):
453 bl_idname = "VIEW3D_GGT_vr_landmarks"
454 bl_label = "VR Landmark Indicators"
455 bl_space_type = 'VIEW_3D'
456 bl_region_type = 'WINDOW'
457 bl_options = {'3D', 'PERSISTENT', 'SCALE'}
459 @classmethod
460 def poll(cls, context):
461 view3d = context.space_data
462 return (
463 view3d.shading.vr_show_landmarks
466 def setup(self, context):
467 pass
469 def draw_prepare(self, context):
470 # first delete the old gizmos
471 for g in self.gizmos:
472 self.gizmos.remove(g)
474 scene = context.scene
475 landmarks = scene.vr_landmarks
477 for lm in landmarks:
478 if ((lm.type == 'SCENE_CAMERA' and not scene.camera) or
479 (lm.type == 'OBJECT' and not lm.base_pose_object)):
480 continue
482 gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
483 gizmo.aspect = 1 / 3, 1 / 4
485 gizmo.color = gizmo.color_highlight = 0.2, 1.0, 0.6
486 gizmo.alpha = 1.0
488 self.gizmo = gizmo
490 if lm.type == 'SCENE_CAMERA':
491 cam = scene.camera
492 lm_mat = cam.matrix_world if cam else Matrix.Identity(4)
493 elif lm.type == 'OBJECT':
494 lm_mat = lm.base_pose_object.matrix_world
495 else:
496 angle = lm.base_pose_angle
497 raw_rot = Euler((radians(90.0), 0, angle))
499 rotmat = Matrix.Identity(3)
500 rotmat.rotate(raw_rot)
501 rotmat.resize_4x4()
503 transmat = Matrix.Translation(lm.base_pose_location)
505 lm_mat = transmat @ rotmat
507 self.gizmo.matrix_basis = lm_mat
510 classes = (
511 VIEW3D_OT_vr_landmark_add,
512 VIEW3D_OT_vr_landmark_remove,
513 VIEW3D_OT_vr_landmark_activate,
514 VIEW3D_OT_vr_landmark_from_session,
515 VIEW3D_OT_vr_camera_landmark_from_session,
516 VIEW3D_OT_add_camera_from_vr_landmark,
517 VIEW3D_OT_camera_to_vr_landmark,
518 VIEW3D_OT_vr_landmark_from_camera,
519 VIEW3D_OT_cursor_to_vr_landmark,
520 VIEW3D_OT_update_vr_landmark,
522 VIEW3D_GT_vr_camera_cone,
523 VIEW3D_GT_vr_controller_grip,
524 VIEW3D_GT_vr_controller_aim,
525 VIEW3D_GGT_vr_viewer_pose,
526 VIEW3D_GGT_vr_controller_poses,
527 VIEW3D_GGT_vr_landmarks,
531 def register():
532 for cls in classes:
533 bpy.utils.register_class(cls)
536 def unregister():
537 for cls in classes:
538 bpy.utils.unregister_class(cls)