UNPKG

polygonjs-engine

Version:

node-based webgl 3D engine https://polygonjs.com

268 lines (267 loc) 9.71 kB
import {Vector2 as Vector22} from "three/src/math/Vector2"; import {Vector3 as Vector32} from "three/src/math/Vector3"; import {Vector4 as Vector42} from "three/src/math/Vector4"; import {Quaternion as Quaternion2} from "three/src/math/Quaternion"; import {Operation} from "./TimelineBuilder"; import {ParamType as ParamType2} from "../../engine/poly/ParamType"; import {TypeAssert} from "../../engine/poly/Assert"; import {AnimNodeEasing} from "./Constant"; import {Poly as Poly2} from "../../engine/Poly"; import {CoreType} from "../Type"; const PROPERTY_SEPARATOR = "."; export class TimelineBuilderProperty { constructor() { } setName(name) { this._property_name = name; } set_target_value(value) { this._target_value = value; } name() { return this._property_name; } target_value() { return this._target_value; } clone() { const cloned = new TimelineBuilderProperty(); if (this._property_name) { cloned.setName(this._property_name); } if (this._target_value != null) { const new_target_value = CoreType.isNumber(this._target_value) ? this._target_value : this._target_value.clone(); cloned.set_target_value(new_target_value); } return cloned; } add_to_timeline(timeline_builder, scene, timeline, target) { const objects = target.objects(scene); if (objects) { this._populate_with_objects(objects, timeline_builder, timeline); } else { const node = target.node(scene); if (node) { this._populate_with_node(node, timeline_builder, timeline); } } } _populate_with_objects(objects, timeline_builder, timeline) { if (!this._property_name) { Poly2.warn("no property name given"); return; } if (this._target_value == null) { Poly2.warn("no target value given"); return; } const operation = timeline_builder.operation(); const update_callback = timeline_builder.update_callback(); for (let object3d of objects) { const props = this._scene_graph_props(object3d, this._property_name); if (props) { let {target_property, to_target, property_names} = props; const vars = this._common_vars(timeline_builder); if (update_callback && update_callback.update_matrix()) { const old_matrix_auto_update = object3d.matrixAutoUpdate; vars.onStart = () => { object3d.matrixAutoUpdate = true; }; vars.onComplete = () => { object3d.matrixAutoUpdate = old_matrix_auto_update; }; } if (target_property instanceof Quaternion2 && this._target_value instanceof Quaternion2) { const proxy = {value: 0}; const qTarget = target_property; const qStart = new Quaternion2().copy(target_property); const qEnd = this._target_value; vars.onUpdate = () => { Quaternion2.slerp(qStart, qEnd, qTarget, proxy.value); }; to_target = proxy; vars.value = 1; } if (CoreType.isNumber(this._target_value)) { if (CoreType.isNumber(target_property)) { for (let property_name of property_names) { vars[property_name] = this.with_op(target_property, this._target_value, operation); } } } else { if (!CoreType.isNumber(target_property)) { for (let property_name of property_names) { vars[property_name] = this.with_op(target_property[property_name], this._target_value[property_name], operation); } } } if (to_target) { this._start_timeline(timeline_builder, timeline, vars, to_target); } } } } _scene_graph_props(object, property_name) { const elements = property_name.split(PROPERTY_SEPARATOR); if (elements.length > 1) { const first_element = elements.shift(); const sub_object = object[first_element]; if (sub_object) { const sub_property_name = elements.join(PROPERTY_SEPARATOR); return this._scene_graph_props(sub_object, sub_property_name); } } else { const target_property = object[property_name]; let to_target = null; const property_names = []; if (CoreType.isNumber(target_property)) { to_target = object; property_names.push(property_name); } else { to_target = target_property; if (this._target_value instanceof Vector22) { property_names.push("x", "y"); } if (this._target_value instanceof Vector32) { property_names.push("x", "y", "z"); } if (this._target_value instanceof Vector42) { property_names.push("x", "y", "z", "w"); } if (this._target_value instanceof Quaternion2) { } } return { target_property, to_target, property_names }; } } _populate_with_node(node, timeline_builder, timeline) { const target_param = node.p[this._property_name]; if (!target_param) { Poly2.warn(`${this._property_name} not found on node ${node.fullPath()}`); return; } if (target_param) { this._populate_vars_for_param(target_param, timeline_builder, timeline); } } _populate_vars_for_param(param, timeline_builder, timeline) { switch (param.type()) { case ParamType2.FLOAT: { this._populate_vars_for_param_float(param, timeline_builder, timeline); } case ParamType2.VECTOR2: { this._populate_vars_for_param_vector2(param, timeline_builder, timeline); } case ParamType2.VECTOR3: { this._populate_vars_for_param_vector3(param, timeline_builder, timeline); } case ParamType2.VECTOR4: { this._populate_vars_for_param_vector4(param, timeline_builder, timeline); } } } _populate_vars_for_param_float(param, timeline_builder, timeline) { if (!CoreType.isNumber(this._target_value)) { Poly2.warn("value is not a numbber", this._target_value); return; } const vars = this._common_vars(timeline_builder); const proxy = {num: param.value}; vars.onUpdate = () => { param.set(proxy.num); }; const operation = timeline_builder.operation(); vars.num = this.with_op(param.value, this._target_value, operation); this._start_timeline(timeline_builder, timeline, vars, proxy); } _populate_vars_for_param_vector2(param, timeline_builder, timeline) { if (!(this._target_value instanceof Vector22)) { return; } const vars = this._common_vars(timeline_builder); const proxy = param.value.clone(); const proxy_array = [0, 0]; vars.onUpdate = () => { proxy.toArray(proxy_array); param.set(proxy_array); }; const operation = timeline_builder.operation(); vars.x = this.with_op(param.value.x, this._target_value.x, operation); vars.y = this.with_op(param.value.y, this._target_value.y, operation); this._start_timeline(timeline_builder, timeline, vars, proxy); } _populate_vars_for_param_vector3(param, timeline_builder, timeline) { if (!(this._target_value instanceof Vector32)) { return; } const vars = this._common_vars(timeline_builder); const proxy = param.value.clone(); const proxy_array = [0, 0, 0]; vars.onUpdate = () => { proxy.toArray(proxy_array); param.set(proxy_array); }; const operation = timeline_builder.operation(); vars.x = this.with_op(param.value.x, this._target_value.x, operation); vars.y = this.with_op(param.value.y, this._target_value.y, operation); vars.z = this.with_op(param.value.z, this._target_value.z, operation); this._start_timeline(timeline_builder, timeline, vars, proxy); } _populate_vars_for_param_vector4(param, timeline_builder, timeline) { if (!(this._target_value instanceof Vector42)) { return; } const vars = this._common_vars(timeline_builder); const proxy = param.value.clone(); const proxy_array = [0, 0, 0, 0]; vars.onUpdate = () => { proxy.toArray(proxy_array); param.set(proxy_array); }; const operation = timeline_builder.operation(); vars.x = this.with_op(param.value.x, this._target_value.x, operation); vars.y = this.with_op(param.value.y, this._target_value.y, operation); vars.z = this.with_op(param.value.z, this._target_value.z, operation); vars.w = this.with_op(param.value.w, this._target_value.w, operation); this._start_timeline(timeline_builder, timeline, vars, proxy); } with_op(current_value, value, operation) { switch (operation) { case Operation.SET: return value; case Operation.ADD: return current_value + value; case Operation.SUBSTRACT: return current_value - value; } TypeAssert.unreachable(operation); } _common_vars(timeline_builder) { const duration = timeline_builder.duration(); const vars = {duration}; const easing = timeline_builder.easing() || AnimNodeEasing.NONE; if (easing) { vars.ease = easing; } const delay = timeline_builder.delay(); if (delay != null) { vars.delay = delay; } const repeat_params = timeline_builder.repeat_params(); if (repeat_params) { vars.repeat = repeat_params.count; vars.repeatDelay = repeat_params.delay; vars.yoyo = repeat_params.yoyo; } return vars; } _start_timeline(timeline_builder, timeline, vars, target) { const position = timeline_builder.position(); const position_param = position ? position.to_parameter() : void 0; timeline.to(target, vars, position_param); } }