feat: action refactoring
This commit is contained in:
@ -19,11 +19,179 @@
|
||||
import bpy
|
||||
import mathutils
|
||||
import copy
|
||||
import logging
|
||||
import numpy as np
|
||||
from enum import Enum
|
||||
|
||||
from .. import utils
|
||||
from .bl_datablock import BlDatablock
|
||||
|
||||
# WIP
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ENUM_EASING_TYPE = [
|
||||
'AUTO',
|
||||
'EAS_IN',
|
||||
'EASE_OUT',
|
||||
'EASE_IN_OUT']
|
||||
|
||||
ENUM_HANDLE_TYPE = [
|
||||
'FREE',
|
||||
'ALIGNED',
|
||||
'VECTOR',
|
||||
'AUTO',
|
||||
'AUTO_CLAMPED']
|
||||
|
||||
ENUM_INTERPOLATION_TYPE = [
|
||||
'CONSTANT',
|
||||
'LINEAR',
|
||||
'BEZIER',
|
||||
'SINE',
|
||||
'QUAD',
|
||||
'CUBIC',
|
||||
'QUART',
|
||||
'QUINT',
|
||||
'EXPO',
|
||||
'CIRC',
|
||||
'BACK',
|
||||
'BOUNCE',
|
||||
'ELASTIC']
|
||||
|
||||
ENUM_KEY_TYPE = [
|
||||
'KEYFRAME',
|
||||
'BREAKDOWN',
|
||||
'MOVING_HOLD',
|
||||
'EXTREME',
|
||||
'JITTER']
|
||||
|
||||
#TODO: Automatic enum and numpy dump and loading
|
||||
|
||||
def dump_fcurve(fcurve, use_numpy=True):
|
||||
""" Dump a sigle curve to a dict
|
||||
|
||||
:arg fcurve: fcurve to dump
|
||||
:type fcurve: bpy.types.FCurve
|
||||
:arg use_numpy: use numpy to eccelerate dump
|
||||
:type use_numpy: bool
|
||||
:return: dict
|
||||
"""
|
||||
fcurve_data = {
|
||||
"data_path": fcurve.data_path,
|
||||
"dumped_array_index": fcurve.array_index,
|
||||
"use_numpy": use_numpy
|
||||
}
|
||||
|
||||
if use_numpy:
|
||||
keyframes_count = len(fcurve.keyframe_points)
|
||||
|
||||
k_amplitude = np.empty(keyframes_count, dtype=np.float64)
|
||||
fcurve.keyframe_points.foreach_get('amplitude', k_amplitude)
|
||||
k_co = np.empty(keyframes_count*2, dtype=np.float64)
|
||||
fcurve.keyframe_points.foreach_get('co', k_co)
|
||||
k_back = np.empty(keyframes_count, dtype=np.float64)
|
||||
fcurve.keyframe_points.foreach_get('back', k_back)
|
||||
k_handle_left = np.empty(keyframes_count*2, dtype=np.float64)
|
||||
fcurve.keyframe_points.foreach_get('handle_left', k_handle_left)
|
||||
k_handle_right = np.empty(keyframes_count*2, dtype=np.float64)
|
||||
fcurve.keyframe_points.foreach_get('handle_right', k_handle_right)
|
||||
|
||||
fcurve_data['amplitude'] = k_amplitude.tobytes()
|
||||
fcurve_data['co'] = k_co.tobytes()
|
||||
fcurve_data['back'] = k_back.tobytes()
|
||||
fcurve_data['handle_left'] = k_handle_left.tobytes()
|
||||
fcurve_data['handle_right'] = k_handle_right.tobytes()
|
||||
|
||||
fcurve_data['easing'] = [ENUM_EASING_TYPE.index(p.easing) for p in fcurve.keyframe_points]
|
||||
fcurve_data['handle_left_type'] = [ENUM_HANDLE_TYPE.index(p.handle_left_type) for p in fcurve.keyframe_points]
|
||||
fcurve_data['handle_right_type'] = [ENUM_HANDLE_TYPE.index(p.handle_right_type) for p in fcurve.keyframe_points]
|
||||
fcurve_data['type'] = [ENUM_KEY_TYPE.index(p.type) for p in fcurve.keyframe_points]
|
||||
fcurve_data['interpolation'] = [ENUM_INTERPOLATION_TYPE.index(p.interpolation) for p in fcurve.keyframe_points]
|
||||
|
||||
else: # Legacy method
|
||||
dumper = utils.dump_anything.Dumper()
|
||||
fcurve_data["keyframe_points"] = []
|
||||
|
||||
for k in fcurve.keyframe_points:
|
||||
fcurve_data["keyframe_points"].append(
|
||||
dumper.dump(k)
|
||||
)
|
||||
|
||||
return fcurve_data
|
||||
|
||||
def load_fcurve(fcurve_data, fcurve):
|
||||
""" Load a dumped fcurve
|
||||
|
||||
:arg fcurve_data: a dumped fcurve
|
||||
:type fcurve_data: dict
|
||||
:arg fcurve: fcurve to dump
|
||||
:type fcurve: bpy.types.FCurve
|
||||
"""
|
||||
use_numpy = fcurve_data.get('use_numpy')
|
||||
|
||||
keyframe_points = fcurve.keyframe_points
|
||||
|
||||
# Remove all keyframe points
|
||||
for i in range(len(keyframe_points)):
|
||||
keyframe_points.remove(keyframe_points[0], fast=True)
|
||||
|
||||
if use_numpy:
|
||||
k_amplitude = np.frombuffer(fcurve_data['amplitude'], dtype=np.float64)
|
||||
|
||||
keyframe_count = len(k_amplitude)
|
||||
|
||||
k_co = np.frombuffer(fcurve_data['co'], dtype=np.float64)
|
||||
k_back = np.frombuffer(fcurve_data['back'], dtype=np.float64)
|
||||
k_amplitude = np.frombuffer(fcurve_data['amplitude'], dtype=np.float64)
|
||||
k_handle_left= np.frombuffer(fcurve_data['handle_left'], dtype=np.float64)
|
||||
k_handle_right= np.frombuffer(fcurve_data['handle_right'], dtype=np.float64)
|
||||
|
||||
keyframe_points.add(keyframe_count)
|
||||
|
||||
keyframe_points.foreach_set('co',k_co)
|
||||
keyframe_points.foreach_set('back',k_back)
|
||||
keyframe_points.foreach_set('amplitude',k_amplitude)
|
||||
keyframe_points.foreach_set('handle_left',k_handle_left)
|
||||
keyframe_points.foreach_set('handle_right',k_handle_right)
|
||||
|
||||
for index, point in enumerate(keyframe_points):
|
||||
point.type = ENUM_KEY_TYPE[fcurve_data['type'][index]]
|
||||
point.easing = ENUM_EASING_TYPE[fcurve_data['easing'][index]]
|
||||
point.handle_left_type = ENUM_HANDLE_TYPE[fcurve_data['handle_left_type'][index]]
|
||||
point.handle_right_type = ENUM_HANDLE_TYPE[fcurve_data['handle_right_type'][index]]
|
||||
point.interpolation = ENUM_INTERPOLATION_TYPE[fcurve_data['interpolation'][index]]
|
||||
|
||||
else:
|
||||
# paste dumped keyframes
|
||||
for dumped_keyframe_point in fcurve_data["keyframe_points"]:
|
||||
if dumped_keyframe_point['type'] == '':
|
||||
dumped_keyframe_point['type'] = 'KEYFRAME'
|
||||
|
||||
new_kf = keyframe_points.insert(
|
||||
dumped_keyframe_point["co"][0],
|
||||
dumped_keyframe_point["co"][1],
|
||||
options={'FAST', 'REPLACE'}
|
||||
)
|
||||
|
||||
keycache = copy.copy(dumped_keyframe_point)
|
||||
keycache = utils.dump_anything.remove_items_from_dict(
|
||||
keycache,
|
||||
["co", "handle_left", "handle_right", 'type']
|
||||
)
|
||||
|
||||
utils.dump_anything.load(new_kf, keycache)
|
||||
|
||||
new_kf.type = dumped_keyframe_point['type']
|
||||
new_kf.handle_left = [
|
||||
dumped_keyframe_point["handle_left"][0],
|
||||
dumped_keyframe_point["handle_left"][1]
|
||||
]
|
||||
new_kf.handle_right = [
|
||||
dumped_keyframe_point["handle_right"][0],
|
||||
dumped_keyframe_point["handle_right"][1]
|
||||
]
|
||||
|
||||
fcurve.update()
|
||||
|
||||
|
||||
|
||||
class BlAction(BlDatablock):
|
||||
bl_id = "actions"
|
||||
@ -37,25 +205,6 @@ class BlAction(BlDatablock):
|
||||
return bpy.data.actions.new(data["name"])
|
||||
|
||||
def _load(self, data, target):
|
||||
begin_frame = 100000
|
||||
end_frame = -100000
|
||||
|
||||
for dumped_fcurve in data["fcurves"]:
|
||||
begin_frame = min(
|
||||
begin_frame,
|
||||
min(
|
||||
[begin_frame] + [dkp["co"][0] for dkp in dumped_fcurve["keyframe_points"]]
|
||||
)
|
||||
)
|
||||
end_frame = max(
|
||||
end_frame,
|
||||
max(
|
||||
[end_frame] + [dkp["co"][0] for dkp in dumped_fcurve["keyframe_points"]]
|
||||
)
|
||||
)
|
||||
begin_frame = 0
|
||||
|
||||
loader = utils.dump_anything.Loader()
|
||||
for dumped_fcurve in data["fcurves"]:
|
||||
dumped_data_path = dumped_fcurve["data_path"]
|
||||
dumped_array_index = dumped_fcurve["dumped_array_index"]
|
||||
@ -65,53 +214,14 @@ class BlAction(BlDatablock):
|
||||
if fcurve is None:
|
||||
fcurve = target.fcurves.new(dumped_data_path, index=dumped_array_index)
|
||||
|
||||
|
||||
# remove keyframes within dumped_action range
|
||||
for keyframe in reversed(fcurve.keyframe_points):
|
||||
if end_frame >= (keyframe.co[0] + begin_frame ) >= begin_frame:
|
||||
fcurve.keyframe_points.remove(keyframe, fast=True)
|
||||
|
||||
# paste dumped keyframes
|
||||
for dumped_keyframe_point in dumped_fcurve["keyframe_points"]:
|
||||
if dumped_keyframe_point['type'] == '':
|
||||
dumped_keyframe_point['type'] = 'KEYFRAME'
|
||||
|
||||
new_kf = fcurve.keyframe_points.insert(
|
||||
dumped_keyframe_point["co"][0] - begin_frame,
|
||||
dumped_keyframe_point["co"][1],
|
||||
options={'FAST', 'REPLACE'}
|
||||
)
|
||||
|
||||
keycache = copy.copy(dumped_keyframe_point)
|
||||
keycache = utils.dump_anything.remove_items_from_dict(
|
||||
keycache,
|
||||
["co", "handle_left", "handle_right",'type']
|
||||
)
|
||||
|
||||
loader.load(
|
||||
new_kf,
|
||||
keycache
|
||||
)
|
||||
|
||||
new_kf.type = dumped_keyframe_point['type']
|
||||
new_kf.handle_left = [
|
||||
dumped_keyframe_point["handle_left"][0] - begin_frame,
|
||||
dumped_keyframe_point["handle_left"][1]
|
||||
]
|
||||
new_kf.handle_right = [
|
||||
dumped_keyframe_point["handle_right"][0] - begin_frame,
|
||||
dumped_keyframe_point["handle_right"][1]
|
||||
]
|
||||
|
||||
# clearing (needed for blender to update well)
|
||||
if len(fcurve.keyframe_points) == 0:
|
||||
target.fcurves.remove(fcurve)
|
||||
target.id_root= data['id_root']
|
||||
load_fcurve(dumped_fcurve, fcurve)
|
||||
target.id_root = data['id_root']
|
||||
|
||||
def _dump(self, pointer=None):
|
||||
start = utils.current_milli_time()
|
||||
assert(pointer)
|
||||
dumper = utils.dump_anything.Dumper()
|
||||
dumper.exclude_filter =[
|
||||
dumper.exclude_filter = [
|
||||
'name_full',
|
||||
'original',
|
||||
'use_fake_user',
|
||||
@ -124,27 +234,14 @@ class BlAction(BlDatablock):
|
||||
'users'
|
||||
]
|
||||
dumper.depth = 1
|
||||
data = dumper.dump(pointer)
|
||||
|
||||
data = dumper.dump(pointer)
|
||||
|
||||
data["fcurves"] = []
|
||||
dumper.depth = 2
|
||||
|
||||
for fcurve in self.pointer.fcurves:
|
||||
fc = {
|
||||
"data_path": fcurve.data_path,
|
||||
"dumped_array_index": fcurve.array_index,
|
||||
"keyframe_points": []
|
||||
}
|
||||
|
||||
for k in fcurve.keyframe_points:
|
||||
fc["keyframe_points"].append(
|
||||
dumper.dump(k)
|
||||
)
|
||||
|
||||
data["fcurves"].append(fc)
|
||||
data["fcurves"].append(dump_fcurve(fcurve, use_numpy=True))
|
||||
|
||||
logger.error(
|
||||
f"{self.pointer.name} dumping time: {utils.current_milli_time()-start} ms")
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user