Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def register():

# Prefs
bpy.utils.register_class(preferences.PreferenceNaming)
bpy.utils.register_class(preferences.PreferenceInputMapping)
bpy.utils.register_class(preferences.ResetNicknamesOperator)
bpy.utils.register_class(preferences.Preferences)
preferences.initialize_preferences()
Expand Down Expand Up @@ -107,6 +108,7 @@ def unregister():
# Prefs
bpy.utils.unregister_class(preferences.Preferences)
bpy.utils.unregister_class(preferences.ResetNicknamesOperator)
bpy.utils.unregister_class(preferences.PreferenceInputMapping)
bpy.utils.unregister_class(preferences.PreferenceNaming)

# Props
Expand Down
88 changes: 71 additions & 17 deletions tracking_toolkit/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,37 +89,91 @@ class PreferenceNaming(bpy.types.PropertyGroup):
)


class PreferenceInputMapping(bpy.types.PropertyGroup):
# Reusable types.
INPUT_TYPE_PROPERTY = bpy.props.EnumProperty(
name="Input Type",
items=[
("Trigger", "Trigger", "Controller Trigger"),
("Grip", "Grip", "Controller Grip"),
("A", "A", "A Button"),
("B", "B", "B Button"),
("X", "X", "X Button"),
("Y", "Y", "Y Button"),
],
)
INPUT_ROLE_PROPERTY = bpy.props.EnumProperty(
name="Input Tracker Role",
items=[
("None", "None", "None"),
*[(n, n, n) for i, n in enumerate(all_role_strings)],
],
)

# Actual properties.
toggle_capture_role: INPUT_ROLE_PROPERTY
toggle_capture_input: INPUT_TYPE_PROPERTY
frame_forward_role: INPUT_ROLE_PROPERTY
frame_forward_input: INPUT_TYPE_PROPERTY
frame_backward_role: INPUT_ROLE_PROPERTY
frame_backward_input: INPUT_TYPE_PROPERTY


class Preferences(bpy.types.AddonPreferences):
bl_idname = base_package

record_at_scene_fps: bpy.props.BoolProperty(default=True)
record_custom_fps: bpy.props.IntProperty(default=24, min=1, max=120, soft_max=90)

input_mapping: bpy.props.PointerProperty(type=PreferenceInputMapping)

naming: bpy.props.CollectionProperty(
name="Default Tracker Nicknames", type=PreferenceNaming
)

def draw(self, _):
layout = self.layout
def _draw_recording_options(self):
rec_box = self.layout.box()
rec_box.label(text="Recording Options", icon="TIME")

layout.label(text="Recording Options")

layout.prop(self, "record_at_scene_fps", text="Record at Scene FPS")
rec_box.prop(self, "record_at_scene_fps", text="Record at Scene FPS")
if not self.record_at_scene_fps:
layout.prop(self, "record_custom_fps", text="Custom FPS")
layout.label(text="Warning: Using custom FPS. Subframes may be created.")
layout.label(text="High scene or custom FPS can cause performance issues.")

layout.separator_spacer()

# Tracker nickname options.

layout.label(text="Tracker Nicknames")
layout.label(
rec_box.prop(self, "record_custom_fps", text="Custom FPS")
rec_box.label(text="Warning: Using custom FPS. Subframes may be created.")
rec_box.label(text="High scene or custom FPS can cause performance issues.")

def _draw_input_options(self):
ipt_box = self.layout.box()
ipt_box.label(text="Input Mapping", icon="MOUSE_LMB")

def _draw_input_map(text: str, action_name: str):
"""
Utility to draw a tracker role/input mapping.
"""
row = ipt_box.row()
if getattr(self.input_mapping, f"{action_name}_role", None) == "None":
row.prop(self.input_mapping, f"{action_name}_role", text=text)
row.label(text="")
else:
row.prop(self.input_mapping, f"{action_name}_role", text=text)
row.prop(self.input_mapping, f"{action_name}_input", text="")

_draw_input_map("Start/Stop Capture", "toggle_capture")
_draw_input_map("Frame Forward", "frame_forward")
_draw_input_map("Frame Backward", "frame_backward")

def _draw_nickname_options(self):
nn_box = self.layout.box()
nn_box.label(text="Tracker Nicknames", icon="TEXT")
nn_box.label(
text="These apply going forward, and will not replace the current nicknames in your scene."
)

for n in self.naming:
layout.prop(n, "nickname", text=n.role_string)
nn_box.prop(n, "nickname", text=n.role_string)

nn_box.operator(ResetNicknamesOperator.bl_idname, text="Reset Nicknames")

layout.operator(ResetNicknamesOperator.bl_idname, text="Reset Nicknames")
def draw(self, _):
self._draw_recording_options()
self._draw_input_options()
self._draw_nickname_options()
30 changes: 25 additions & 5 deletions tracking_toolkit/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,21 @@ def convert_bones_to_empties():
fcurves = anim_utils.action_get_channelbag_for_slot(
empty_action, empty_action.slots[0]
).fcurves
for fcurve in fcurves:
# Only get the fcurve for the current tracker's bone.
if not fcurve.data_path.startswith(f'pose.bones["{nickname}"].'):
for fcurve in fcurves[:]:
# Remove copied fcurves that belong to other bones.
if not fcurve.data_path.startswith(f'pose.bones["{nickname}"]'):
fcurves.remove(fcurve)
continue

new_path = re.sub(r".+\.([^.]+)$", r"\1", fcurve.data_path)
new_path = re.sub(r".+]\.?(.+)$", r"\1", fcurve.data_path)

# Ensure custom prop exists.
# It is a custom prop if surrounded by brackets and quotes.
# Strip these brackets and quotes for the custom prop name.
if new_path.startswith('["'):
prop_name = re.sub(r"\[\"(.+)\"]", r"\1", new_path)
empty[prop_name] = float(0)

fcurve.data_path = new_path

# If the armature had an active (non-strip) action, set it as active.
Expand Down Expand Up @@ -503,7 +511,19 @@ def convert_empties_to_bones():
).fcurves

for empty_fcurve in empty_fcurves:
new_path = f'pose.bones["{nickname}"].{empty_fcurve.data_path}'
data_path = empty_fcurve.data_path

# If surrounded by quotes and brackets, this is a custom property fcurve.
# Ensure the custom property exists.
if empty_fcurve.data_path.startswith('["'):
new_path = f'pose.bones["{nickname}"]{data_path}'
prop_name = re.sub(r"\[\"(.+)\"]", r"\1", data_path)
bone[prop_name] = float(0)

# Otherwise, standard channel (loc, rot, etc.)
# Use a dot instead of quotes and brackets.
else:
new_path = f'pose.bones["{nickname}"].{data_path}'

# Remove existing fcurve if present.
arm_fcurve = arm_fcurves.find(new_path, index=empty_fcurve.array_index)
Expand Down
31 changes: 0 additions & 31 deletions tracking_toolkit/xr_core/actions.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,4 @@
import re
from dataclasses import dataclass


@dataclass
class ActionData:
name: str
action_path: str
subaction_path: str


# Default actions.
default_action_data = [
ActionData(
name="left_hand",
action_path="/user/hand/left",
subaction_path="/input/grip/pose",
),
ActionData(
name="right_hand",
action_path="/user/hand/right",
subaction_path="/input/grip/pose",
),
]

# Vive tracker actions.
vive_role_strings = [
Expand All @@ -43,14 +20,6 @@ class ActionData:
"camera",
"keyboard",
]
vive_tracker_action_data = [
ActionData(
name=role,
action_path=f"/user/vive_tracker_htcx/role/{role}",
subaction_path="/input/grip/pose",
)
for role in vive_role_strings
]

all_role_strings = ["head", "left_hand", "right_hand", *vive_role_strings]

Expand Down
Loading
Loading