@awayjs/scene
Version:
AwayJS scene classes
716 lines (593 loc) • 25.3 kB
text/typescript
import { WaveAudio, ColorTransform, IAsset, Matrix3D } from '@awayjs/core';
import { BlendMode } from '@awayjs/stage';
import { HierarchicalProperty } from '@awayjs/view';
import { Graphics } from '@awayjs/graphics';
import { IDisplayObjectAdapter } from '../adapters/IDisplayObjectAdapter';
import { IFilter } from '../adapters/IFilter';
import { IMovieClipAdapter } from '../adapters/IMovieClipAdapter';
import { MovieClip } from '../display/MovieClip';
import { Sprite } from '../display/Sprite';
import { MorphSprite } from '../display/MorphSprite';
import { DisplayObject } from '../display/DisplayObject';
import { DisplayObjectContainer } from '../display/DisplayObjectContainer';
import { ISceneGraphFactory } from '../factories/ISceneGraphFactory';
import { IFrameLabel } from './IFrameLabel';
import { TimelineActionType as AType } from './TimelineActionType';
import { IFrameScript } from './IFrameScript';
const BLEND_MODES = [
'', BlendMode.NORMAL, BlendMode.LAYER,
BlendMode.MULTIPLY, BlendMode.SCREEN,
BlendMode.LIGHTEN, BlendMode.DARKEN,
BlendMode.DIFFERENCE, BlendMode.ADD,
BlendMode.SUBTRACT, BlendMode.INVERT,
BlendMode.ALPHA, BlendMode.ERASE, BlendMode.OVERLAY,
BlendMode.HARDLIGHT
];
function mapBlendIdToString(id: number = 1): string {
return BLEND_MODES[id] || BLEND_MODES[1];
}
type TApplyFunction = (timeline: Timeline, child: DisplayObject, ratget: MovieClip, i: number) => void;
export class Timeline {
public static readonly applyFunctionMap: Record<AType, TApplyFunction > = {
[AType.UPDATE_MTX]: Timeline.update_mtx_all,
[AType.UPDATE_CMTX]: Timeline.update_colortransform,
[AType.UPDATE_MASKS]: Timeline.update_masks,
[AType.UPDATE_NAME]: Timeline.update_name,
[AType.UPDATE_BUTTON_NAME]: Timeline.update_button_name,
[AType.UPDATE_VISIBLE]: Timeline.update_visibility,
[AType.UPDATE_BLENDMODE]: Timeline.update_blendmode,
[AType.UPDATE_RENDERMODE]: Timeline.update_rendermode,
[AType.UPDATE_FILTERS]: Timeline.update_filters,
[AType.UPDATE_SCALE_ROT]: Timeline.update_mtx_scale_rot,
[AType.UPDATE_POS]: Timeline.update_mtx_pos,
[AType.ENABLE_MASKMODE]: Timeline.enable_maskmode,
[AType.REMOVE_MASK]: Timeline.remove_masks,
[AType.SWAP_GRAPHICS]: Timeline.swap_graphics,
[AType.SET_RATIO]: Timeline.set_ratio,
[AType.START_AUDIO]: Timeline.start_audio
};
private _blocked: boolean;
public _update_indices: number[] = [];
public _update_frames: number[] = [];
public isButton: boolean = false;
public _labels: StringMap<IFrameLabel>; // dictionary to store label => keyframeindex
public avm1InitActions: Object; // dictionary to store keyframeindex => ExecuteScriptCommand
public avm1ButtonActions: any[]; // dictionary to store keyframeindex => ExecuteScriptCommand
public avm1Exports: Object; // dictionary to store keyframeindex => ExecuteScriptCommand
// framescripts are not stored by keyframe-index, but by frameIdx
// this makes it easy to get/set framescripts on the fly, even when no keyframe exists for that frame
private _framescripts: StringMap<IFrameScript[]>;
private _framescripts_translated: Object;
public keyframe_to_frameidx: Object;
public keyframe_indices: number[]; //stores 1 keyframeindex per frameindex
public keyframe_firstframes: number[]; //stores the firstframe of each keyframe
public keyframe_constructframes: number[]; //stores the previous fullConstruct keyframeindex
public keyframe_durations: ArrayBufferView; //only needed to calulcate other arrays
// synched:
public frame_command_indices: ArrayBufferView;
public frame_recipe: ArrayBufferView;
// synched:
public command_index_stream: ArrayBufferView;
public command_length_stream: ArrayBufferView;
public add_child_stream: ArrayBufferView;
public add_sounds_stream: ArrayBufferView;
public remove_child_stream: ArrayBufferView;
public update_child_stream: ArrayBufferView;
public update_child_props_length_stream: ArrayBufferView;
public update_child_props_indices_stream: ArrayBufferView;
public property_index_stream: ArrayBufferView;
public property_type_stream: ArrayBufferView;
public properties_stream_int: ArrayBufferView;
// property_values_stream:
public properties_stream_f32_mtx_all: ArrayBufferView; // list of floats
public properties_stream_f32_mtx_scale_rot: ArrayBufferView; // list of floats
public properties_stream_f32_mtx_pos: ArrayBufferView; // list of floats
public properties_stream_f32_ct: ArrayBufferView; // list of floats
public properties_stream_strings: string[];
public properties_stream_filters: IFilter[];
public placeObjectTagsForSessionIDs: NumberMap<any>;
public graphicsPool: any;
public audioPool: any;
public numKeyFrames: number;
/**
* in AS3 framescript are getting added to mc by calling "mc.addFrameScript" from within the mc.constructor
* because timelines are shared between all instances of a mc,
* only the first instance of a mc should be allowd to add framescripts to the timeline
* to check this, we track the id of mc-instance that adds the first framescript,
* and only allow additional framescripts to be added from same instance
**/
private _initalMcID: number;
constructor(readonly factory: ISceneGraphFactory) {
this._initalMcID = -1;
this.numKeyFrames = 0;
this.keyframe_indices = [];
this.avm1Exports = {};
this.avm1InitActions = {};
this.avm1ButtonActions = [];
this.graphicsPool = {};
this.audioPool = {};
this.placeObjectTagsForSessionIDs = {};
this._labels = {};
this._framescripts = {};
this._framescripts_translated = {};
this.keyframe_to_frameidx = {};
}
public resetScripts() {
this._framescripts = {};
this._framescripts_translated = {};
}
/* should be called after timeline-streams have been set.
prepares
*/
public init(): void {
if ((this.frame_command_indices == null) || (this.frame_recipe == null) || (this.keyframe_durations == null)) {
return;
}
let frame_cnt = 0;
let ic = 0;
let ic2 = 0;
let duration = 0;
let keyframe_cnt = 0;
let last_construct_frame = 0;
this.keyframe_firstframes = [];
this.keyframe_constructframes = [];
this.keyframe_indices = [];
this.keyframe_to_frameidx = {};
this.keyframe_to_frameidx[0] = 0;
let duration_all = 0;
for (ic = 0; ic < this.numKeyFrames; ic++) {
this.keyframe_to_frameidx[ic] = duration_all;
duration = this.keyframe_durations[(ic)];
duration_all += duration;
if (this.frame_recipe[ic] & 1)
last_construct_frame = keyframe_cnt;
this.keyframe_firstframes[keyframe_cnt] = frame_cnt;
this.keyframe_constructframes[keyframe_cnt++] = last_construct_frame;
for (ic2 = 0; ic2 < duration; ic2++)
this.keyframe_indices[frame_cnt++] = ic;
}
}
/**
* for AS3:
* - called from constructor of MC
* for AS2:
* - called when decoding swf-tags to timeline-streams
* @param script -
* @param frame_idx - the index of the frame (not the keyframe-index)
* @param target_mc - the mc-instance that is calling this function
*/
public add_framescript(script: any, frame_idx: number, target_mc: MovieClip, isAVM1: boolean = false): void {
if (this._initalMcID >= 0 && target_mc.id != this._initalMcID)
return;
this._initalMcID = target_mc.id;
if (!this._framescripts[frame_idx]) {
this._framescripts[frame_idx] = [];
}
if (Array.isArray(script)) {
for (let i = 0; i < script.length; i++) {
this._framescripts[frame_idx][this._framescripts[frame_idx].length] = script[i];
}
} else {
this._framescripts[frame_idx].push(script);
}
this._framescripts_translated[frame_idx] = !isAVM1;
}
/**
* get a array of framescripts for a specific frame
* for AVM1 "checkForTranslation" should be true, so we get translated framescripts
* @param target_mc
* @param frame_idx
* @param checkForTranslation
*/
public get_script_for_frame(
target_mc: MovieClip,
frame_idx: number,
checkForTranslation: boolean = false): IFrameScript[] {
if (frame_idx >= 0 && this._framescripts[frame_idx]) {
if (checkForTranslation && !this._framescripts_translated[frame_idx]) {
// todo: cleanup so we can retrieve className of target_mc without hacks
const name = (<any>target_mc).className ? (<any>target_mc).className : target_mc.name;
this._framescripts[frame_idx] = this.factory.createFrameScripts(
this._framescripts[frame_idx],
frame_idx,
name,
target_mc.id);
this._framescripts_translated[frame_idx] = true;
}
return this._framescripts[frame_idx];
}
return null;
}
public get numFrames(): number {
return this.keyframe_indices.length;
}
public getKeyframeIndexForFrameIndex(frame_index: number): number {
return this.keyframe_indices[frame_index];
}
public getChildInstance(symbolID: number, sessionID: number) {
return this.factory.createChildInstanceForTimeline(this, symbolID, sessionID);
}
public extractHitArea(target_mc: MovieClip): DisplayObjectContainer {
target_mc.reset(false);
this.gotoFrame(target_mc, this.numFrames - 1, false);
let i: number = target_mc.numChildren;
const hitArea: DisplayObjectContainer = new DisplayObjectContainer();
let child: DisplayObject;
let originalChild: DisplayObject;
while (i > 0) {
i--;
originalChild = target_mc.getChildAt(i);
child = originalChild.clone();
//child.reset();
child.x = originalChild.x;
child.scaleX = originalChild.scaleX;
child.y = originalChild.y;
child.scaleY = originalChild.scaleY;
child.rotationZ = originalChild.rotationZ;
hitArea.addChild(child);
}
hitArea.pickObjectFromTimeline = true;
target_mc.pickObject = hitArea;
target_mc.reset(false);
return hitArea;
}
/**
* Get the label at the current frame of the target_mc MovieClip instance.
* If the current frame has no label, it returns null
* @param target_mc
*/
public getCurrentFrameLabel(target_mc: MovieClip): string {
const firstFrameIdxOfCurKeyFrame = this.keyframe_to_frameidx[target_mc.constructedKeyFrameIndex];
for (const key in this._labels) {
if (this._labels[key].keyFrameIndex == target_mc.constructedKeyFrameIndex &&
firstFrameIdxOfCurKeyFrame == target_mc.currentFrameIndex) {
return this._labels[key].name;
}
}
return null;
}
/**
* Get the label at the current frame of the target_mc MovieClip instance.
* If the current frame has no label it returns the name of the previous frame that includes a label.
* If the current frame and previous frames do not include a label, it returns null
* @param target_mc
*/
public getCurrentLabel(target_mc: MovieClip): string {
let label: string = null;
let lastLabelframeIdx: number = -1;
for (const key in this._labels) {
const keyIndex = this._labels[key].keyFrameIndex;
if (keyIndex > lastLabelframeIdx && keyIndex <= target_mc.constructedKeyFrameIndex) {
lastLabelframeIdx = keyIndex;
label = this._labels[key].name;
}
}
return label;
}
public jumpToLabel(target_mc: MovieClip, label: string, offset: number = 0): void {
if (!this._labels[label]) {
console.warn('[TIMELINE] - jumpToLabel with invalid label', target_mc, label, offset);
return;
}
const key_frame_index: number = this._labels[label].keyFrameIndex;
if (key_frame_index >= 0)
target_mc.currentFrameIndex = this.keyframe_firstframes[key_frame_index] + offset;
}
/**
* Get scripts for a specific frame
* atm this is only called from AVM1MovieClip._callFrame
* @param target_mc
* @param label
* @param isAVM1
*/
public getScriptForLabel(target_mc: MovieClip, label: string, isAVM1: boolean = false): IFrameScript[] {
const key_frame_index: number = this._labels[label.toLowerCase()].keyFrameIndex;
if (key_frame_index < 0)
return null;
const frameIdx: number = this.keyframe_firstframes[key_frame_index];
if (frameIdx >= 0 && this._framescripts[frameIdx]) {
return this.get_script_for_frame(target_mc, frameIdx, isAVM1);
}
return null;
}
/**
* move the playhead of the timeline to a specific frame
* @param target_mc
* @param frame_idx
* @param queue_script
* @param queue_pass2
* @param forceReconstruct
*/
public gotoFrame(target_mc: MovieClip, frame_idx: number,
queue_script: boolean = true,
queue_pass2: boolean = false,
forceReconstruct: boolean = false): void {
const current_keyframe_idx: number = target_mc.constructedKeyFrameIndex;
const target_keyframe_idx: number = this.keyframe_indices[frame_idx];
if (current_keyframe_idx == target_keyframe_idx && !forceReconstruct) {
(<IMovieClipAdapter>target_mc.adapter).queueFrameScripts(this, frame_idx, queue_script);
return;
} else if (current_keyframe_idx + 1 == target_keyframe_idx) {
// target_keyframe_idx is the next keyframe. we can just use constructnext for this
this.constructNextFrame(target_mc, queue_script, true);
return;
}
// when constructing a frame we must start constructing
// either at the beginning of the timeline, or at a frame where all object was removed
// construct_keyframe_idx is the index of the first keyframe we must process
const construct_keyframe_idx: number = this.keyframe_constructframes[target_keyframe_idx];
// 3 keyframes:
// - current_keyframe_idx
// - target_keyframe_idx
// - construct_keyframe_idx
// normally construction must start at construct_keyframe_idx
// if we jump forward, and target_keyframe_idx >
let start_construct_idx: number = construct_keyframe_idx;
const jump_forward: boolean = (target_keyframe_idx > current_keyframe_idx);
if (jump_forward && current_keyframe_idx > construct_keyframe_idx)
start_construct_idx = current_keyframe_idx + 1;
(<IMovieClipAdapter>target_mc.adapter).constructFrame(this, start_construct_idx,
target_keyframe_idx,
jump_forward,
frame_idx,
queue_pass2,
queue_script);
// apply update commands for objects still on stage (only if they are not blocked by script)
this.applyCollectedUpdateCommands(target_mc);
target_mc.constructedKeyFrameIndex = target_keyframe_idx;
}
public applyCollectedUpdateCommands(target_mc: MovieClip): void {
let k: number;
const len: number = this._update_indices.length;
for (k = 0; k < len; k++)
this.update_childs(target_mc, this._update_indices[k], this._update_frames[k]);
}
/**
* constructs the next frame of the timeline
* expects the target_mc.currentFrameIndex to already be set to the next frame
* @param target_mc
* @param queueScript
* @param scriptPass1
*/
public constructNextFrame(target_mc: MovieClip, queueScript: boolean = true, scriptPass1: boolean = false): void {
const frameIndex: number = target_mc.currentFrameIndex;
const new_keyFrameIndex: number = this.keyframe_indices[frameIndex];
if (queueScript)
(<IMovieClipAdapter>target_mc.adapter).queueFrameScripts(this, frameIndex, scriptPass1);
if (target_mc.constructedKeyFrameIndex != new_keyFrameIndex) {
target_mc.constructedKeyFrameIndex = new_keyFrameIndex;
let frame_command_idx = this.frame_command_indices[new_keyFrameIndex];
const frame_recipe = this.frame_recipe[new_keyFrameIndex];
if (frame_recipe & 1) {
(<IMovieClipAdapter>target_mc.adapter).removeAllTimelineChilds();
} else if (frame_recipe & 2) {
this.remove_childs_continous(target_mc, frame_command_idx++);
}
if (frame_recipe & 4)
this.add_childs_continous(target_mc, frame_command_idx++);
if (frame_recipe & 8)
this.update_childs(target_mc, frame_command_idx++);
if (frame_recipe & 16)
this.start_sounds(target_mc, frame_command_idx++);
}
}
public remove_childs_continous(sourceMovieClip: MovieClip, frame_command_idx: number): void {
const start_index: number = this.command_index_stream[frame_command_idx];
const end_index: number = start_index + this.command_length_stream[frame_command_idx];
for (let i: number = start_index; i < end_index; i++) {
// in avm1 we remove by depth, in avm2 we remove by sessionID
(<IMovieClipAdapter>sourceMovieClip.adapter).removeTimelineChildAt(this.remove_child_stream[i]);
}
}
public add_childs_continous(target_mc: MovieClip, frame_command_idx: number): void {
let idx: number;
const start_index: number = this.command_index_stream[frame_command_idx];
const end_index: number = start_index + this.command_length_stream[frame_command_idx];
for (let i: number = start_index; i < end_index; i++) {
idx = i * 3;
if (typeof this.add_child_stream[idx] === 'undefined') {
console.warn('[Timeline] - add_childs_continous - could not find child-id in child_stream for idx',
idx, this.add_child_stream);
continue;
}
const childAsset: IAsset = this.factory.createChildInstanceForTimeline(this,
this.add_child_stream[idx + 2], this.add_child_stream[idx]);
(<IMovieClipAdapter>target_mc.adapter).addTimelineChildAtDepth(<DisplayObject>childAsset,
this.add_child_stream[idx + 1]);
}
}
public start_sounds(target_mc: MovieClip, frame_command_idx: number): void {
const start_index: number = this.command_index_stream[frame_command_idx];
const end_index: number = start_index + this.command_length_stream[frame_command_idx];
for (let i: number = start_index; i < end_index; i++) {
const audioProps: any = this.audioPool[this.add_sounds_stream[i]];
if (audioProps) {
const sound: WaveAudio = audioProps.sound;
if (!sound) {
console.warn('[Timeline] Missing sound in audioProps!', audioProps);
return;
}
if (audioProps.cmd == 15) {// start sound
target_mc.startSound(sound, audioProps.props.loopCount || 0);
} else if (audioProps.cmd == 16) {// stop sound
target_mc.stopSound(sound);
}
//console.log("start sound:", child);
}
}
}
public update_childs(target_mc: MovieClip, frame_command_idx: number, frameIdx: number = -1): void {
const start = this.command_index_stream[frame_command_idx];
const end = start + this.command_length_stream[frame_command_idx];
for (let i = start; i < end; i++) {
const child = target_mc.getTimelineChildAtSessionID(this.update_child_stream[i]);
if (!child) {
continue;
}
// check if the child is blocked by script for transform
this._blocked = !!(child._adapter && (<IDisplayObjectAdapter> child.adapter).isBlockedByScript());
const propsStart = this.update_child_props_indices_stream[i];
const propsEnd = propsStart + this.update_child_props_length_stream[i];
for (let p = propsStart; p < propsEnd; p++) {
Timeline.applyFunctionMap[this.property_type_stream[p]] (
this,
child,
target_mc,
this.property_index_stream[p]
);
}
}
}
public static update_mtx_all(timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number): void {
if (timeline._blocked || (<any>child).noTimelineUpdate)
return;
i *= 6;
const new_matrix: Matrix3D = child.transform.matrix3D;
const props_stream = timeline.properties_stream_f32_mtx_all;
new_matrix._rawData[0] = props_stream[i++];
new_matrix._rawData[1] = props_stream[i++];
new_matrix._rawData[4] = props_stream[i++];
new_matrix._rawData[5] = props_stream[i++];
new_matrix._rawData[12] = props_stream[i++];
new_matrix._rawData[13] = props_stream[i];
child.transform.invalidateComponents();
}
public static update_colortransform(
timeline: Timeline,child: DisplayObject, _target_mc: MovieClip, i: number
): void {
if (child._adapter && (<IDisplayObjectAdapter> child.adapter).isColorTransformByScript())
return;
i *= 8;
const props_stream = timeline.properties_stream_f32_ct;
const new_ct = child.transform.colorTransform || (child.transform.colorTransform = new ColorTransform());
new_ct._rawData[0] = props_stream[i++];
new_ct._rawData[1] = props_stream[i++];
new_ct._rawData[2] = props_stream[i++];
new_ct._rawData[3] = props_stream[i++];
new_ct._rawData[4] = props_stream[i++];
new_ct._rawData[5] = props_stream[i++];
new_ct._rawData[6] = props_stream[i++];
new_ct._rawData[7] = props_stream[i];
child.transform.invalidateColorTransform();
}
public static update_masks(timeline: Timeline, child: DisplayObject, target_mc: MovieClip, i: number): void {
// an object could have a multiple groups of masks, in case a graphic clip was merged into the timeline
// this is not implemented in the runtime yet
// for now, a second mask-group would overwrite the first one
const masks: Array<DisplayObject> = [];
const numMasks = timeline.properties_stream_int[i++];
if (numMasks === 0) {
child.updateTimelineMask(null);
return;
}
//mask may not exist if a goto command moves the playhead to a point in the timeline after
//one of the masks in a mask array has already been removed. Therefore a check is needed.
for (let m = 0; m < numMasks; m++) {
masks.push(target_mc.getTimelineChildAtSessionID(timeline.properties_stream_int[i + m]));
}
child.updateTimelineMask(masks);
}
public static update_name(timeline: Timeline, child: DisplayObject, target_mc: MovieClip, i: number): void {
if (timeline.properties_stream_strings[i].indexOf('instance') == 0) {
return;
}
(<IMovieClipAdapter>target_mc.adapter).unregisterScriptObject(child);
child.name = timeline.properties_stream_strings[i];
(<IMovieClipAdapter> target_mc.adapter).registerScriptObject(child);
}
public static update_button_name(
timeline: Timeline, target: DisplayObject, sourceMovieClip: MovieClip, i: number
): void {
target.name = timeline.properties_stream_strings[i];
(<MovieClip> target).addButtonListeners();
(<IMovieClipAdapter> sourceMovieClip.adapter).registerScriptObject(target);
}
public static update_visibility(_timeline: Timeline, child: DisplayObject, target_mc: MovieClip, i: number): void {
if (!child._adapter || !(<IDisplayObjectAdapter> child.adapter).isVisibilityByScript()) {
child.visible = !!i;
}
}
public static update_mtx_scale_rot(
timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number
): void {
if (timeline._blocked || (<any>child).noTimelineUpdate) {
return;
}
i *= 4;
const new_matrix: Matrix3D = child.transform.matrix3D;
const props_stream = timeline.properties_stream_f32_mtx_scale_rot;
new_matrix._rawData[0] = props_stream[i++];
new_matrix._rawData[1] = props_stream[i++];
new_matrix._rawData[4] = props_stream[i++];
new_matrix._rawData[5] = props_stream[i];
child.transform.invalidateComponents();
child._invalidateHierarchicalProperty(HierarchicalProperty.SCENE_TRANSFORM);
}
public static update_mtx_pos(timeline: Timeline, child: DisplayObject, target_mc: MovieClip, i: number): void {
if (timeline._blocked || (<any>child).noTimelineUpdate)
return;
i *= 2;
const new_matrix = child.transform.matrix3D;
new_matrix._rawData[12] = timeline.properties_stream_f32_mtx_pos[i++];
new_matrix._rawData[13] = timeline.properties_stream_f32_mtx_pos[i];
child.transform.invalidatePosition();
}
public static enable_maskmode(_timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, _i: number): void {
child.maskMode = true;
}
public static remove_masks(_timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, _i: number): void {
child.updateTimelineMask(null);
}
public static update_filters(timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number): void {
const startFilter: number = timeline.properties_stream_int[i++];
const numFilter: number = timeline.properties_stream_int[i++];
const adapter = <IDisplayObjectAdapter>child.adapter;
if (numFilter === 0) {
adapter.updateFilters(null);
return;
}
adapter.updateFilters(
timeline.properties_stream_filters.slice(startFilter, startFilter + numFilter)
);
}
public static swap_graphics(timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number): void {
if (!child.isAsset(Sprite)) {
console.warn('[Timeline] - swap_graphics - child is not a Sprite');
return;
}
const sprite = <Sprite>child;
const target = <Graphics> timeline.graphicsPool[timeline.properties_stream_int[i]];
if (target.id === sprite.graphics.id) {
// already the same graphics
return;
}
sprite.graphics = target;
}
public static start_audio(_timeline: Timeline, _child: DisplayObject, _target_mc: MovieClip, _i: number): void {}
public static set_ratio(_timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number): void {
if (!child.isAsset(MorphSprite)) {
console.warn('[Timeline] - set_ratio - child is not a MorphSprite');
return;
}
(<MorphSprite>child).setRatio(_timeline.properties_stream_int[i] / 0xffff);
}
public static update_blendmode(_timeline: Timeline, child: DisplayObject, _target_mc: MovieClip, i: number): void {
child.blendMode = mapBlendIdToString(i);
}
public static update_rendermode(
_timeline: Timeline, _child: DisplayObject, _target_mc: MovieClip, i: number): void {
console.log('update rendermode ' + i);
}
public dispose() {
this.keyframe_indices = [];
this.avm1Exports = {};
this.avm1InitActions = {};
this.avm1ButtonActions = [];
this.graphicsPool = {};
this.audioPool = {};
this.placeObjectTagsForSessionIDs = {};
this._labels = {};
this._framescripts = {};
this._framescripts_translated = {};
}
}