UNPKG

@awayjs/scene

Version:
526 lines (525 loc) 24.1 kB
var _a; import { ColorTransform } from '@awayjs/core'; import { BlendMode } from '@awayjs/stage'; import { HierarchicalProperty } from '@awayjs/view'; import { Sprite } from '../display/Sprite'; import { MorphSprite } from '../display/MorphSprite'; import { DisplayObjectContainer } from '../display/DisplayObjectContainer'; var 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) { if (id === void 0) { id = 1; } return BLEND_MODES[id] || BLEND_MODES[1]; } var Timeline = /** @class */ (function () { function Timeline(factory) { this.factory = factory; this._update_indices = []; this._update_frames = []; this.isButton = false; 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 = {}; } Timeline.prototype.resetScripts = function () { this._framescripts = {}; this._framescripts_translated = {}; }; /* should be called after timeline-streams have been set. prepares */ Timeline.prototype.init = function () { if ((this.frame_command_indices == null) || (this.frame_recipe == null) || (this.keyframe_durations == null)) { return; } var frame_cnt = 0; var ic = 0; var ic2 = 0; var duration = 0; var keyframe_cnt = 0; var last_construct_frame = 0; this.keyframe_firstframes = []; this.keyframe_constructframes = []; this.keyframe_indices = []; this.keyframe_to_frameidx = {}; this.keyframe_to_frameidx[0] = 0; var 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 */ Timeline.prototype.add_framescript = function (script, frame_idx, target_mc, isAVM1) { if (isAVM1 === void 0) { isAVM1 = false; } 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 (var 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 */ Timeline.prototype.get_script_for_frame = function (target_mc, frame_idx, checkForTranslation) { if (checkForTranslation === void 0) { checkForTranslation = false; } 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 var name_1 = target_mc.className ? target_mc.className : target_mc.name; this._framescripts[frame_idx] = this.factory.createFrameScripts(this._framescripts[frame_idx], frame_idx, name_1, target_mc.id); this._framescripts_translated[frame_idx] = true; } return this._framescripts[frame_idx]; } return null; }; Object.defineProperty(Timeline.prototype, "numFrames", { get: function () { return this.keyframe_indices.length; }, enumerable: false, configurable: true }); Timeline.prototype.getKeyframeIndexForFrameIndex = function (frame_index) { return this.keyframe_indices[frame_index]; }; Timeline.prototype.getChildInstance = function (symbolID, sessionID) { return this.factory.createChildInstanceForTimeline(this, symbolID, sessionID); }; Timeline.prototype.extractHitArea = function (target_mc) { target_mc.reset(false); this.gotoFrame(target_mc, this.numFrames - 1, false); var i = target_mc.numChildren; var hitArea = new DisplayObjectContainer(); var child; var originalChild; 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 */ Timeline.prototype.getCurrentFrameLabel = function (target_mc) { var firstFrameIdxOfCurKeyFrame = this.keyframe_to_frameidx[target_mc.constructedKeyFrameIndex]; for (var 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 */ Timeline.prototype.getCurrentLabel = function (target_mc) { var label = null; var lastLabelframeIdx = -1; for (var key in this._labels) { var keyIndex = this._labels[key].keyFrameIndex; if (keyIndex > lastLabelframeIdx && keyIndex <= target_mc.constructedKeyFrameIndex) { lastLabelframeIdx = keyIndex; label = this._labels[key].name; } } return label; }; Timeline.prototype.jumpToLabel = function (target_mc, label, offset) { if (offset === void 0) { offset = 0; } if (!this._labels[label]) { console.warn('[TIMELINE] - jumpToLabel with invalid label', target_mc, label, offset); return; } var key_frame_index = 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 */ Timeline.prototype.getScriptForLabel = function (target_mc, label, isAVM1) { if (isAVM1 === void 0) { isAVM1 = false; } var key_frame_index = this._labels[label.toLowerCase()].keyFrameIndex; if (key_frame_index < 0) return null; var frameIdx = 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 */ Timeline.prototype.gotoFrame = function (target_mc, frame_idx, queue_script, queue_pass2, forceReconstruct) { if (queue_script === void 0) { queue_script = true; } if (queue_pass2 === void 0) { queue_pass2 = false; } if (forceReconstruct === void 0) { forceReconstruct = false; } var current_keyframe_idx = target_mc.constructedKeyFrameIndex; var target_keyframe_idx = this.keyframe_indices[frame_idx]; if (current_keyframe_idx == target_keyframe_idx && !forceReconstruct) { 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 var construct_keyframe_idx = 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 > var start_construct_idx = construct_keyframe_idx; var jump_forward = (target_keyframe_idx > current_keyframe_idx); if (jump_forward && current_keyframe_idx > construct_keyframe_idx) start_construct_idx = current_keyframe_idx + 1; 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; }; Timeline.prototype.applyCollectedUpdateCommands = function (target_mc) { var k; var len = 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 */ Timeline.prototype.constructNextFrame = function (target_mc, queueScript, scriptPass1) { if (queueScript === void 0) { queueScript = true; } if (scriptPass1 === void 0) { scriptPass1 = false; } var frameIndex = target_mc.currentFrameIndex; var new_keyFrameIndex = this.keyframe_indices[frameIndex]; if (queueScript) target_mc.adapter.queueFrameScripts(this, frameIndex, scriptPass1); if (target_mc.constructedKeyFrameIndex != new_keyFrameIndex) { target_mc.constructedKeyFrameIndex = new_keyFrameIndex; var frame_command_idx = this.frame_command_indices[new_keyFrameIndex]; var frame_recipe = this.frame_recipe[new_keyFrameIndex]; if (frame_recipe & 1) { 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++); } }; Timeline.prototype.remove_childs_continous = function (sourceMovieClip, frame_command_idx) { var start_index = this.command_index_stream[frame_command_idx]; var end_index = start_index + this.command_length_stream[frame_command_idx]; for (var i = start_index; i < end_index; i++) { // in avm1 we remove by depth, in avm2 we remove by sessionID sourceMovieClip.adapter.removeTimelineChildAt(this.remove_child_stream[i]); } }; Timeline.prototype.add_childs_continous = function (target_mc, frame_command_idx) { var idx; var start_index = this.command_index_stream[frame_command_idx]; var end_index = start_index + this.command_length_stream[frame_command_idx]; for (var i = 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; } var childAsset = this.factory.createChildInstanceForTimeline(this, this.add_child_stream[idx + 2], this.add_child_stream[idx]); target_mc.adapter.addTimelineChildAtDepth(childAsset, this.add_child_stream[idx + 1]); } }; Timeline.prototype.start_sounds = function (target_mc, frame_command_idx) { var start_index = this.command_index_stream[frame_command_idx]; var end_index = start_index + this.command_length_stream[frame_command_idx]; for (var i = start_index; i < end_index; i++) { var audioProps = this.audioPool[this.add_sounds_stream[i]]; if (audioProps) { var sound = 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); } } }; Timeline.prototype.update_childs = function (target_mc, frame_command_idx, frameIdx) { if (frameIdx === void 0) { frameIdx = -1; } var start = this.command_index_stream[frame_command_idx]; var end = start + this.command_length_stream[frame_command_idx]; for (var i = start; i < end; i++) { var 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 && child.adapter.isBlockedByScript()); var propsStart = this.update_child_props_indices_stream[i]; var propsEnd = propsStart + this.update_child_props_length_stream[i]; for (var p = propsStart; p < propsEnd; p++) { Timeline.applyFunctionMap[this.property_type_stream[p]](this, child, target_mc, this.property_index_stream[p]); } } }; Timeline.update_mtx_all = function (timeline, child, _target_mc, i) { if (timeline._blocked || child.noTimelineUpdate) return; i *= 6; var new_matrix = child.transform.matrix3D; var 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(); }; Timeline.update_colortransform = function (timeline, child, _target_mc, i) { if (child._adapter && child.adapter.isColorTransformByScript()) return; i *= 8; var props_stream = timeline.properties_stream_f32_ct; var 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(); }; Timeline.update_masks = function (timeline, child, target_mc, i) { // 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 var masks = []; var 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 (var m = 0; m < numMasks; m++) { masks.push(target_mc.getTimelineChildAtSessionID(timeline.properties_stream_int[i + m])); } child.updateTimelineMask(masks); }; Timeline.update_name = function (timeline, child, target_mc, i) { if (timeline.properties_stream_strings[i].indexOf('instance') == 0) { return; } target_mc.adapter.unregisterScriptObject(child); child.name = timeline.properties_stream_strings[i]; target_mc.adapter.registerScriptObject(child); }; Timeline.update_button_name = function (timeline, target, sourceMovieClip, i) { target.name = timeline.properties_stream_strings[i]; target.addButtonListeners(); sourceMovieClip.adapter.registerScriptObject(target); }; Timeline.update_visibility = function (_timeline, child, target_mc, i) { if (!child._adapter || !child.adapter.isVisibilityByScript()) { child.visible = !!i; } }; Timeline.update_mtx_scale_rot = function (timeline, child, _target_mc, i) { if (timeline._blocked || child.noTimelineUpdate) { return; } i *= 4; var new_matrix = child.transform.matrix3D; var 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); }; Timeline.update_mtx_pos = function (timeline, child, target_mc, i) { if (timeline._blocked || child.noTimelineUpdate) return; i *= 2; var 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(); }; Timeline.enable_maskmode = function (_timeline, child, _target_mc, _i) { child.maskMode = true; }; Timeline.remove_masks = function (_timeline, child, _target_mc, _i) { child.updateTimelineMask(null); }; Timeline.update_filters = function (timeline, child, _target_mc, i) { var startFilter = timeline.properties_stream_int[i++]; var numFilter = timeline.properties_stream_int[i++]; var adapter = child.adapter; if (numFilter === 0) { adapter.updateFilters(null); return; } adapter.updateFilters(timeline.properties_stream_filters.slice(startFilter, startFilter + numFilter)); }; Timeline.swap_graphics = function (timeline, child, _target_mc, i) { if (!child.isAsset(Sprite)) { console.warn('[Timeline] - swap_graphics - child is not a Sprite'); return; } var sprite = child; var target = timeline.graphicsPool[timeline.properties_stream_int[i]]; if (target.id === sprite.graphics.id) { // already the same graphics return; } sprite.graphics = target; }; Timeline.start_audio = function (_timeline, _child, _target_mc, _i) { }; Timeline.set_ratio = function (_timeline, child, _target_mc, i) { if (!child.isAsset(MorphSprite)) { console.warn('[Timeline] - set_ratio - child is not a MorphSprite'); return; } child.setRatio(_timeline.properties_stream_int[i] / 0xffff); }; Timeline.update_blendmode = function (_timeline, child, _target_mc, i) { child.blendMode = mapBlendIdToString(i); }; Timeline.update_rendermode = function (_timeline, _child, _target_mc, i) { console.log('update rendermode ' + i); }; Timeline.prototype.dispose = function () { this.keyframe_indices = []; this.avm1Exports = {}; this.avm1InitActions = {}; this.avm1ButtonActions = []; this.graphicsPool = {}; this.audioPool = {}; this.placeObjectTagsForSessionIDs = {}; this._labels = {}; this._framescripts = {}; this._framescripts_translated = {}; }; Timeline.applyFunctionMap = (_a = {}, _a[1 /* AType.UPDATE_MTX */] = Timeline.update_mtx_all, _a[2 /* AType.UPDATE_CMTX */] = Timeline.update_colortransform, _a[3 /* AType.UPDATE_MASKS */] = Timeline.update_masks, _a[4 /* AType.UPDATE_NAME */] = Timeline.update_name, _a[5 /* AType.UPDATE_BUTTON_NAME */] = Timeline.update_button_name, _a[6 /* AType.UPDATE_VISIBLE */] = Timeline.update_visibility, _a[7 /* AType.UPDATE_BLENDMODE */] = Timeline.update_blendmode, _a[8 /* AType.UPDATE_RENDERMODE */] = Timeline.update_rendermode, _a[9 /* AType.UPDATE_FILTERS */] = Timeline.update_filters, _a[11 /* AType.UPDATE_SCALE_ROT */] = Timeline.update_mtx_scale_rot, _a[12 /* AType.UPDATE_POS */] = Timeline.update_mtx_pos, _a[200 /* AType.ENABLE_MASKMODE */] = Timeline.enable_maskmode, _a[201 /* AType.REMOVE_MASK */] = Timeline.remove_masks, _a[202 /* AType.SWAP_GRAPHICS */] = Timeline.swap_graphics, _a[203 /* AType.SET_RATIO */] = Timeline.set_ratio, _a[204 /* AType.START_AUDIO */] = Timeline.start_audio, _a); return Timeline; }()); export { Timeline };