polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
268 lines (267 loc) • 9.71 kB
JavaScript
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);
}
}