Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EDITOR-#620. Finish partially load frames of selected dancers/time range #628

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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: 1 addition & 1 deletion editor-blender/client/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ async def subscribe():
logger.info("Subscription cancelled.")
break

except Exception as e:
except Exception as _:
logger.exception("Subscription closed with error.")
fut.cancel()

Expand Down
99 changes: 95 additions & 4 deletions editor-blender/core/actions/property/animation_data/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ....log import logger
from ....models import ControlMapElement, MapID, PartType
from ....states import state
from ....utils.algorithms import binary_search_for_range
from ....utils.convert import (
ControlAddAnimationData,
ControlAddCurveData,
Expand All @@ -34,6 +35,7 @@ def reset_control_frames_and_fade_sequence(fade_seq: list[tuple[int, bool]]):
action, "ld_control_frame", keyframe_points=len(fade_seq), clear=True
)

# fade_seq contains only loaded frames
_, kpoints_list = get_keyframe_points(curve)
for i, (start, _) in enumerate(fade_seq):
point = kpoints_list[i]
Expand Down Expand Up @@ -175,15 +177,76 @@ def init_ctrl_keyframes_from_state(dancers_reset: list[bool] | None = None):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

ctrl_map = state.control_map
ctrl_frame_number = len(ctrl_map)

sorted_ctrl_map = sorted(ctrl_map.items(), key=lambda item: item[1].start)
animation_data = control_map_to_animation_data(sorted_ctrl_map)

sorted_frame_ctrl_map = [item[1].start for item in sorted_ctrl_map]
frame_range_l, frame_range_r = state.dancer_load_frames

filtered_ctrl_map_start, filtered_ctrl_map_end = binary_search_for_range(
sorted_frame_ctrl_map, frame_range_l, frame_range_r
)
filtered_ctrl_map = sorted_ctrl_map[
filtered_ctrl_map_start : filtered_ctrl_map_end + 1
]

# state.not_loaded_ctrl_frames: a list of ctrl map ID that is not loaded
not_loaded_ctrl_frames: list[MapID] = []
filtered_index = 0
for sorted_index in range(len(sorted_ctrl_map)):
if filtered_index >= len(filtered_ctrl_map):
not_loaded_ctrl_frames.append(sorted_ctrl_map[sorted_index][0])
elif filtered_ctrl_map[filtered_index][0] != sorted_ctrl_map[sorted_index][0]:
not_loaded_ctrl_frames.append(sorted_ctrl_map[sorted_index][0])
else:
filtered_index += 1
state.not_loaded_control_frames = not_loaded_ctrl_frames

animation_data = control_map_to_animation_data(filtered_ctrl_map)

ctrl_frame_number = len(filtered_ctrl_map)

show_dancer = state.show_dancers

for dancer_index, dancer_item in enumerate(state.dancers_array):
if dancers_reset is not None and not dancers_reset[dancer_index]:
if not show_dancer[dancer_index]:
continue

parts = dancer_item.parts

for part in parts:
part_name = part.name
part_type = part.type

part_obj_name = f"{dancer_index}_{part_name}"
part_obj = data_objects[part_obj_name]

if part_type == PartType.LED:
for led_obj in part_obj.children:
if led_obj.animation_data is not None:
action = cast(
bpy.types.Action | None, led_obj.animation_data.action
)
if action != None:
bpy.data.actions.remove(action, do_unlink=True)

else:
if part_obj.animation_data is not None:
action = cast(
bpy.types.Action | None, part_obj.animation_data.action
)
if action != None:
bpy.data.actions.remove(action, do_unlink=True)

for dancer_index, dancer_item in enumerate(state.dancers_array):
# if ((dancers_reset is not None and not dancers_reset[dancer_index])
# or not show_dancer[dancer_index]
# ):
# continue
if ctrl_frame_number == 0:
break
if not show_dancer[dancer_index]:
continue
dancer_name = dancer_item.name
parts = dancer_item.parts

Expand All @@ -199,6 +262,7 @@ def init_ctrl_keyframes_from_state(dancers_reset: list[bool] | None = None):
if part_type == PartType.LED:
for led_obj in part_obj.children:
position: int = getattr(led_obj, "ld_led_pos")

action = ensure_action(
led_obj, f"{part_obj_name}Action.{position:03}"
)
Expand All @@ -222,10 +286,19 @@ def init_ctrl_keyframes_from_state(dancers_reset: list[bool] | None = None):

# insert fake frame and update fade sequence
scene = bpy.context.scene

if scene.animation_data is not None:
del_action = cast(bpy.types.Action | None, scene.animation_data.action)
if del_action != None:
bpy.data.actions.remove(del_action, do_unlink=True)

if ctrl_frame_number == 0:
return

action = ensure_action(scene, "SceneAction")

if dancers_reset is None or all(dancers_reset):
fade_seq = [(frame.start, frame.fade) for _, frame in sorted_ctrl_map]
fade_seq = [(frame.start, frame.fade) for _, frame in filtered_ctrl_map]
reset_control_frames_and_fade_sequence(fade_seq)


Expand Down Expand Up @@ -329,13 +402,18 @@ def modify_partial_ctrl_keyframes(
):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

show_dancer_dict = dict(zip(state.dancer_names, state.show_dancers))

for dancer_index, dancer_item in enumerate(state.dancers_array):
if dancers_reset is not None and dancers_reset[dancer_index]:
continue

dancer_name = dancer_item.name
parts = dancer_item.parts

if not show_dancer_dict[dancer_name]:
continue

logger.info(f"[CTRL MODIFY] {dancer_name}")

for part in parts:
Expand Down Expand Up @@ -411,10 +489,15 @@ def add_partial_ctrl_single_object_action(
def add_partial_ctrl_keyframes(animation_data: ControlAddAnimationData):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

show_dancer_dict = dict(zip(state.dancer_names, state.show_dancers))

for dancer_index, dancer_item in enumerate(state.dancers_array):
dancer_name = dancer_item.name
parts = dancer_item.parts

if not show_dancer_dict[dancer_name]:
continue

logger.info(f"[CTRL ADD] {dancer_name}")

for part in parts:
Expand Down Expand Up @@ -496,10 +579,14 @@ def edit_partial_ctrl_single_object_action(
def edit_partial_ctrl_keyframes(animation_data: ControlUpdateAnimationData):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

show_dancer_dict = dict(zip(state.dancer_names, state.show_dancers))
for dancer_index, dancer_item in enumerate(state.dancers_array):
dancer_name = dancer_item.name
parts = dancer_item.parts

if not show_dancer_dict[dancer_name]:
continue

logger.info(f"[CTRL UPDATE] {dancer_name}")

for part in parts:
Expand Down Expand Up @@ -562,10 +649,14 @@ def delete_partial_ctrl_single_object_action(
def delete_partial_ctrl_keyframes(animation_data: ControlDeleteAnimationData):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

show_dancer_dict = dict(zip(state.dancer_names, state.show_dancers))
for dancer_index, dancer_item in enumerate(state.dancers_array):
dancer_name = dancer_item.name
parts = dancer_item.parts

if not show_dancer_dict[dancer_name]:
continue

logger.info(f"[CTRL DELETE] {dancer_name}")

for part in parts:
Expand Down
66 changes: 60 additions & 6 deletions editor-blender/core/actions/property/animation_data/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,31 @@
from .....properties.types import RevisionPropertyItemType
from ....models import MapID, PosMapElement
from ....states import state
from ....utils.algorithms import binary_search_for_range
from ....utils.convert import PosModifyAnimationData
from .utils import ensure_action, ensure_curve, get_keyframe_points


def reset_pos_frames():
if not bpy.context:
return

pos_start_record_to_load = []
for index in range(len(state.pos_record)):
if state.pos_record[index] not in state.not_loaded_pos_frames:
pos_start_record_to_load.append(state.pos_start_record[index])

scene = bpy.context.scene
action = ensure_action(scene, "SceneAction")
curve = ensure_curve(
action,
"ld_pos_frame",
keyframe_points=len(state.pos_start_record),
keyframe_points=len(pos_start_record_to_load),
clear=True,
)

_, kpoints_list = get_keyframe_points(curve)
for i, start in enumerate(state.pos_start_record):
for i, start in enumerate(pos_start_record_to_load):
point = kpoints_list[i]
point.co = start, start

Expand Down Expand Up @@ -126,22 +133,64 @@ def init_pos_keyframes_from_state(dancers_reset: list[bool] | None = None):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

pos_map = state.pos_map
pos_frame_number = len(pos_map)

sorted_pos_map = sorted(pos_map.items(), key=lambda item: item[1].start)

for i, (id, pos_map_element) in enumerate(sorted_pos_map):
sorted_frame_pos_map = [item[1].start for item in sorted_pos_map]
frame_range_l, frame_range_r = state.dancer_load_frames

filtered_pos_map_start, filtered_pos_map_end = binary_search_for_range(
sorted_frame_pos_map, frame_range_l, frame_range_r
)
filtered_pos_map = sorted_pos_map[filtered_pos_map_start : filtered_pos_map_end + 1]

# state.not_loaded_pos_frames: a list of pos map ID that is not loaded
not_loaded_pos_frames: list[MapID] = []
filtered_index = 0
for sorted_index in range(len(sorted_pos_map)):
if filtered_index >= len(filtered_pos_map):
not_loaded_pos_frames.append(sorted_pos_map[sorted_index][0])
elif filtered_pos_map[filtered_index][0] != sorted_pos_map[sorted_index][0]:
not_loaded_pos_frames.append(sorted_pos_map[sorted_index][0])
else:
filtered_index += 1
state.not_loaded_pos_frames = not_loaded_pos_frames

pos_frame_number = len(filtered_pos_map)
show_dancer = state.show_dancers

for dancer_name in state.dancer_names:
dancer_index = state.dancer_part_index_map[dancer_name].index
if not show_dancer[dancer_index]:
continue

dancer_obj = data_objects[dancer_name]

if dancer_obj.animation_data is not None:
action = cast(bpy.types.Action | None, dancer_obj.animation_data.action)
if action != None:
bpy.data.actions.remove(action, do_unlink=True)

for i, (id, pos_map_element) in enumerate(filtered_pos_map):
if pos_frame_number == 0:
break

frame_start = pos_map_element.start
pos_status = pos_map_element.pos

for dancer_name, pos in pos_status.items():
dancer_index = state.dancer_part_index_map[dancer_name].index
if dancers_reset and not dancers_reset[dancer_index]:
# if ((dancers_reset and not dancers_reset[dancer_index])
# or not show_dancer[dancer_index]
# ):
# continue
if not show_dancer[dancer_index]:
continue

dancer_location = (pos.x, pos.y, pos.z)

dancer_obj = data_objects[dancer_name]

action = ensure_action(dancer_obj, dancer_name + "Action")

for d in range(3):
Expand All @@ -163,8 +212,8 @@ def init_pos_keyframes_from_state(dancers_reset: list[bool] | None = None):

# insert fake frame
scene = bpy.context.scene
action = ensure_action(scene, "SceneAction")

action = ensure_action(scene, "SceneAction")
curve = ensure_curve(
action, "ld_pos_frame", keyframe_points=pos_frame_number, clear=i == 0
)
Expand Down Expand Up @@ -198,8 +247,12 @@ def init_pos_keyframes_from_state(dancers_reset: list[bool] | None = None):
def modify_partial_pos_keyframes(modify_animation_data: PosModifyAnimationData):
data_objects = cast(dict[str, bpy.types.Object], bpy.data.objects)

show_dancer_dict = dict(zip(state.dancer_names, state.show_dancers))
for dancer_item in state.dancers_array:
dancer_name = dancer_item.name
if not show_dancer_dict[dancer_name]:
continue

dancer_obj = data_objects[dancer_name]

frames = modify_animation_data[dancer_name]
Expand Down Expand Up @@ -227,6 +280,7 @@ def modify_partial_pos_keyframes(modify_animation_data: PosModifyAnimationData):
if curve_index < kpoints_len:
for d in range(3):
point = kpoints_lists[d][curve_index]

curves[d].keyframe_points.remove(point)

kpoints_len = len(kpoints_lists[0])
Expand Down
Loading
Loading