UNPKG

@awayfl/avm1

Version:

Virtual machine for executing AS1 and AS2 code

145 lines (126 loc) 5.22 kB
import { BitmapImage2D, Image2D } from '@awayjs/stage'; import { IFrameScript, Timeline, MovieClip, Sprite, DisplayObjectContainer, Billboard, ISceneGraphFactory, TextField, PrefabBase, DefaultSceneGraphFactory, MorphSprite, DisplayObject, FrameScriptManager } from '@awayjs/scene'; import { MaterialBase, MethodMaterial } from '@awayjs/materials'; import { AVM1Context } from './context'; import { getAVM1Object } from './lib/AVM1Utils'; import { Graphics } from '@awayjs/graphics'; import { IAsset } from '@awayjs/core'; export class AVM1SceneGraphFactory extends DefaultSceneGraphFactory implements ISceneGraphFactory { public static _instance: AVM1SceneGraphFactory; public static get instance(): AVM1SceneGraphFactory { if (!AVM1SceneGraphFactory._instance) { console.log('Error. A instance of AVM1SceneGraphFactory must be created manually \ before accessing the singleton AVM1SceneGraphFactory._instance'); //AVM1SceneGraphFactory._instance=new AVM1SceneGraphFactory(); } return AVM1SceneGraphFactory._instance; } public imageStore: Object = {}; public avm1Context: AVM1Context; constructor(avm1Context: AVM1Context) { super(); this.avm1Context = avm1Context; AVM1SceneGraphFactory._instance = this; } public createSprite(prefab: PrefabBase = null): Sprite { return new Sprite(); } public createDisplayObjectContainer(): DisplayObjectContainer { return new DisplayObjectContainer(); } public createMovieClip(timeline: Timeline = null, symbol: any = null): MovieClip { const awayMovieClip: MovieClip = new MovieClip(timeline || new Timeline(this)); getAVM1Object(awayMovieClip, this.avm1Context); awayMovieClip._symbol = symbol; return awayMovieClip; } public createTextField(): TextField { const awayTextfield: TextField = new TextField(); awayTextfield.multiline = true; awayTextfield.wordWrap = true; getAVM1Object(awayTextfield, this.avm1Context); return awayTextfield; } public createBillboard(material: MaterialBase): Billboard { return null;//new Billboard(); } public createImage2D(width: number, height: number, transparent: boolean = true, fillColor: number = null, powerOfTwo: boolean = true): Image2D { return new BitmapImage2D(width, height, transparent, fillColor, powerOfTwo); } public createFrameScripts(scripts: IFrameScript[], frameIdx: number, objName: string, objID: number) { objName = objName.replace(/[^\w]/g, ''); const outputFrameScripts: IFrameScript[] = []; for (let i = 0; i < scripts.length; i++) { const script = scripts[i]; script.data = this.avm1Context.actionsDataFactory.createActionsData( <any>script, 'script_' + name + '_' + objID + '_frame_' + frameIdx + '_idx_' + i); outputFrameScripts[outputFrameScripts.length] = script; } if (outputFrameScripts.length) { outputFrameScripts.sort(this.compareAVM1FrameScripts); } return outputFrameScripts; } /** * Get a instance for a given SymbolID and assign a sessionID to it. * This is used by timeline to create children * * @param symbolID * @param sessionID */ public createChildInstanceForTimeline(timeline: Timeline, symbolID: number, sessionID: number): IAsset { // if this was called we might have new constructors from timeline to process FrameScriptManager.invalidAS3Constructors = true; const asset: IAsset = this.awaySymbols[symbolID]; let clone: DisplayObject; if (asset.isAsset(Graphics)) { clone = Sprite.getNewSprite(<Graphics> asset.clone());//TODO: remove this clone() without the mem leak clone.mouseEnabled = false; } else if (asset.isAsset(Sprite)) { clone = Sprite.getNewSprite((<Sprite> asset).graphics); clone.mouseEnabled = false; } else if (asset.isAsset(MorphSprite)) { clone = MorphSprite.getNewMorphSprite((<MorphSprite> asset).graphics.clone()); clone.mouseEnabled = false; } else if (asset.isAsset(BitmapImage2D)) { // enable blending for symbols, because if you place image directly on stage // it not enable blend mode const m = new MethodMaterial(<BitmapImage2D>asset); m.alphaBlending = (<BitmapImage2D>asset).transparent; clone = Billboard.getNewBillboard(m); clone.mouseEnabled = false; } else { clone = (<any> asset.adapter).clone(false).adaptee; } const placeObjectTag: any = timeline.placeObjectTagsForSessionIDs[sessionID]; if (placeObjectTag && ((<any>placeObjectTag).variableName || (placeObjectTag.events && placeObjectTag.events.length > 0))) { (<any>clone.adapter).placeObjectTag = placeObjectTag; (<any>clone.adapter).initEvents = placeObjectTag; } clone._sessionID = sessionID; return clone; } // this is used for ordering AVM1 Framescripts into correct order private compareAVM1FrameScripts(a: IFrameScript, b: IFrameScript): number { if (!a.precedence) { return !b.precedence ? 0 : -1; } else if (!b.precedence) { return 1; } let i = 0; while (i < a.precedence.length && i < b.precedence.length && a.precedence[i] === b.precedence[i]) { i++; } if (i >= a.precedence.length) { return a.precedence.length === b.precedence.length ? 0 : -1; } else { return i >= b.precedence.length ? 1 : a.precedence[i] - b.precedence[i]; } } }