diff --git a/mobile_version/application.xml b/mobile_version/application.xml
index fcafcbbd..353e1ec7 100644
--- a/mobile_version/application.xml
+++ b/mobile_version/application.xml
@@ -1,73 +1,105 @@
-
-
- com.distractionware.vvvvvvmobile
- 1.02
- mobileDevice
- VVVVVV
- VVVVVV
-
-
-
-
-
-]]>
-
-
- UIStatusBarStyle
-UIStatusBarStyleBlackOpaque
-UIRequiresPersistentWiFi
-NO
-UIPrerenderedIcon
-
-UIApplicationExitsOnSuspend
-
-UIDeviceFamily
-
-
- 1
-
- 2
-]]>
- standard
-
-
- VVVVVV
- vvvvvv.swf
- true
- landscape
- gpu
- standard
- true
- true
-
-
- icons/icon_48.png
- icons/icon_57.png
- icons/icon_72.png
- icons/icon_76.png
- icons/icon_96.png
- icons/icon_114.png
- icons/icon_120.png
- icons/icon_144.png
- icons/icon_152.png
- icons/icon_512.png
- icons/icon_1024.png
-
-
-
- com.milkmangames.extensions.GameCenter
-
-
+
+
+ com.distractionware.vvvvvvmobile
+ 2.2.1
+ mobileDevice
+ VVVVVV
+ VVVVVV
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+ true
+
+
+ UIStatusBarStyle
+ UIStatusBarStyleBlackOpaque
+ UIRequiresPersistentWiFi
+ NO
+ UIPrerenderedIcon
+
+ UIApplicationExitsOnSuspend
+
+
+ UIDeviceFamily
+
+
+ 1
+
+
+
+
+
+ ]]>
+ high
+
+
+
+ VVVVVV
+ vvvvvv.swf
+ true
+ true
+ standard
+ true
+ landscape
+ direct
+
+
+
+
+ icons/icon_48.png
+ icons/icon_57.png
+ icons/icon_72.png
+ icons/icon_76.png
+ icons/icon_96.png
+ icons/icon_114.png
+ icons/icon_120.png
+ icons/icon_144.png
+ icons/icon_152.png
+ icons/icon_512.png
+ icons/icon_1024.png
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile_version/src/EditorDataclass.as b/mobile_version/src/EditorDataclass.as
index ad88845e..b7766a5b 100644
--- a/mobile_version/src/EditorDataclass.as
+++ b/mobile_version/src/EditorDataclass.as
@@ -1,9 +1,4 @@
package {
- import flash.display.*;
- import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
-
public class EditorDataclass{
public function EditorDataclass():void {
clear();
diff --git a/mobile_version/src/EmbeddedAssets.as b/mobile_version/src/EmbeddedAssets.as
new file mode 100644
index 00000000..350a2338
--- /dev/null
+++ b/mobile_version/src/EmbeddedAssets.as
@@ -0,0 +1,12 @@
+package {
+ public class EmbeddedAssets {
+ /* PNG texture */
+ [Embed(source = "../data/vvvvvv_graphics.png")]
+ public static const vvvvvv_graphics:Class;
+
+ /* XML file */
+ [Embed(source = "../data/vvvvvv_graphics.xml",
+ mimeType = "application/octet-stream")]
+ public static const vvvvvv_graphics_xml:Class;
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/LevelMetaData.as b/mobile_version/src/LevelMetaData.as
index bea5ef71..ac8f3779 100644
--- a/mobile_version/src/LevelMetaData.as
+++ b/mobile_version/src/LevelMetaData.as
@@ -1,5 +1,4 @@
package {
- import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.net.*;
diff --git a/mobile_version/src/Load.as b/mobile_version/src/Load.as
new file mode 100644
index 00000000..5e08380d
--- /dev/null
+++ b/mobile_version/src/Load.as
@@ -0,0 +1,16 @@
+package{
+ import flash.display.Sprite;
+ import starling.core.Starling;
+
+ [SWF(backgroundColor="#000000", frameRate="30")]
+ public class Load extends Sprite{
+ private var _starling:Starling;
+
+ public function Load() {
+ Starling.multitouchEnabled = true;
+
+ _starling = new Starling(Main, stage);
+ _starling.start();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/Main.as b/mobile_version/src/Main.as
index a010f250..2e1e3ba2 100644
--- a/mobile_version/src/Main.as
+++ b/mobile_version/src/Main.as
@@ -1,36 +1,35 @@
-package{
- import flash.display.*;
+package {
import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
- import flash.media.*;
- import flash.text.*;
- import flash.ui.ContextMenu;
- import flash.ui.ContextMenuItem;
- import flash.events.ContextMenuEvent;
+ import flash.net.*;
+ import flash.display.Screen;
+ import flash.display.StageAlign;
+ import flash.display.StageQuality;
+ import flash.display.StageScaleMode;
+ import flash.system.Capabilities;
+ import starling.core.Starling;
+ import starling.display.Image;
+ import starling.text.BitmapFont;
+ import starling.text.TextField;
+ import starling.core.StatsDisplay;
+ import starling.events.Event;
+ import starling.utils.Color;
+ import starling.textures.*;
+ import starling.display.*;
+ import flash.filesystem.File;
+ import starling.events.KeyboardEvent;
import flash.ui.Keyboard;
- import flash.ui.Mouse;
+ import starling.utils.AssetManager;
import bigroom.input.KeyPoll;
- import flash.system.fscommand;
- import flash.system.Capabilities;
+ //import com.mesmotronic.ane.AndroidFullScreen; //This doesn't seem to be needed anymore
+ import flash.display.StageDisplayState;
+ import flash.media.*;
+
+
import flash.utils.getTimer;
import flash.utils.Timer;
- //import com.mesmotronic.ane.AndroidFullScreen;
+ import flash.events.TimerEvent;
- //import com.sociodox.theminer.TheMiner; //Profiler
-
- //Real value
- //[SWF(width = "1136", height = "768", frameRate = "30", backgroundColor = "#000000")] //Set the size and color of the Flash file
- //Big frame for big androids!
- //[SWF(width = "3000", height = "2000", frameRate = "30", backgroundColor = "#000000")] //Set the size and color of the Flash file
- [SWF(frameRate = "30", backgroundColor = "#000000")] //Set the size and color of the Flash file
- //iPad test
- //[SWF(width = "1024", height = "768", frameRate="60", backgroundColor = "#000000")] //Set the size and color of the Flash file
- //iPhone test
- //[SWF(width = "480", height = "320", frameRate="30", backgroundColor = "#000000")] //Set the size and color of the Flash file
- //[SWF(width = "960", height = "640", frameRate="30", backgroundColor = "#000000")] //Set the size and color of the Flash file
-
- public class Main extends Sprite {
+ public class Main extends Sprite{
static public var BLOCK:Number = 0;
static public var TRIGGER:Number = 1;
static public var DAMAGE:Number = 2;
@@ -49,7 +48,11 @@
public var EDITORMODE:int = 8;
public var CONTROLTUTORIALMODE:int = 9;
- public function Main():void {
+ public var addedtwice:Boolean = false;
+
+ public function Main() {
+ super();
+
if (stage) gameinit();
else addEventListener(Event.ADDED_TO_STAGE, gameinit);
}
@@ -57,565 +60,395 @@
private function gameinit(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, gameinit);
// entry point
- var tempbmp:Bitmap;
-
- this.mouseEnabled = false;
- this.mouseChildren = false;
+ if (addedtwice) return; //I don't think I actually need this, but... I have a hunch
+ addedtwice = true;
//Ok: quick security check to make sure it doesn't get posted about
- if (sitelock()) {
- key = new KeyPoll(stage);
+ key = new KeyPoll(Starling.current.nativeStage);
+
+ //immersivemode = AndroidFullScreen.isSupported;
+ stage.addEventListener(Event.RESIZE, function(e:Event):void{
+ androidresize();
+ });
+
+ device.deviceresolution = device.ANDROID;
+
+ editor.init(); //Load in all the levels
+
+ //General game variables
+ obj.init();
+ help.init();
+
+ /*obj.createblock(BLOCK,20,200,128,16);
+ obj.createblock(BLOCK,130,170,128,16);
+ obj.createblock(BLOCK,240,150,128,16);
+ obj.createblock(BLOCK,240,20,128,16);
+ obj.createblock(BLOCK,130,40,128,16);
+ obj.createblock(BLOCK,20,60,128,16);*/
+
+ //Input
+ key.definestickrange(device.xres / 2, 0, 6);
+
+ SoundMixer.soundTransform = new SoundTransform(1);
+
+ music.currentsong = -1; music.musicfade = 0;//no music, no amb
+ music.initefchannels(); music.currentefchan = 0;
+ music.nicechange = -1;
+
+ music.numplays = 0;
+ music.musicchan.push(new music_1()); // 0: Level Complete
+ music.musicchan.push(new vmaintheme_hq()); // 1: VVVVVV Main Theme (Pushing Forward)
+ music.musicchan.push(new vtempo_hq()); // 2: VVVVVV Tempo Theme (Positive Force)
+ music.musicchan.push(new vpfa_hq()); // 3: Potential for Anything
+ music.musicchan.push(new passionforexploring()); // 4: UU Brothers Instrumental
+ music.musicchan.push(new souleye_intermission()); // 5: Jingle: Intermission
+ music.musicchan.push(new presentingvvvvvv()); // 6: Jingle: Menu Loop
+ music.musicchan.push(new music_2()); // 7: Jingle: Game Complete
+ music.musicchan.push(new configmegamix_hq()); // 8: Config Megamix
+ music.musicchan.push(new posreverse()); // 9: Tempo Theme, Reversed
+ music.musicchan.push(new poppot()); // 10: Extra
+ music.musicchan.push(new pipedream_hq()); // 11: Highscore
+ music.musicchan.push(new pressurecooker_hq()); // 12: Pressure Cooker
+ music.musicchan.push(new pacedenergy()); // NEW 13: Paced Energy
+ music.musicchan.push(new piercingthesky()); // NEW 14: Piercing the Sky
+ music.musicchan.push(new predestinedfateremix()); // NEW 15: Predestined Fate Remix
+
+ music.efchan.push(new ef_0());
+ music.efchan.push(new ef_1());
+ music.efchan.push(new ef_2());
+ music.efchan.push(new ef_3());
+ music.efchan.push(new ef_4());
+ music.efchan.push(new ef_5());
+ music.efchan.push(new ef_6());
+ music.efchan.push(new ef_7());
+ music.efchan.push(new ef_8());
+ music.efchan.push(new ef_9());
+ music.efchan.push(new ef_10());
+ music.efchan.push(new ef_11());
+ music.efchan.push(new ef_12());
+ music.efchan.push(new ef_13());
+ music.efchan.push(new ef_14());
+ music.efchan.push(new ef_15());
+ music.efchan.push(new ef_16());
+ music.efchan.push(new ef_17());
+ music.efchan.push(new ef_18());
+ music.efchan.push(new ef_19());
+ music.efchan.push(new ef_20());
+ music.efchan.push(new ef_21());
+ music.efchan.push(new ef_22());
+ music.efchan.push(new ef_23());
+ music.efchan.push(new ef_24());
+ music.efchan.push(new ef_25());
+ music.efchan.push(new ef_26());
+ music.efchan.push(new ef_27());
- //ANDROID SPECIFIC CODE HERE
- /*
- if (AndroidFullScreen.isSupported) {
- if (!AndroidFullScreen.immersiveMode()){
- stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
- device.xres = flash.system.Capabilities.screenResolutionX;
- device.yres = flash.system.Capabilities.screenResolutionY;
- immersivemode = false;
- }else {
- device.xres = stage.stageWidth;
- device.yres = stage.stageHeight;
- immersivemode = true;
- }
- }else {
- */
- stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
- device.xres = flash.system.Capabilities.screenResolutionX;
- device.yres = flash.system.Capabilities.screenResolutionY;
- immersivemode = false;
- //}
+ /*
+ Graphics Init
+ */
+ dwgfx.init(stage);
+ //Load assets
+ dwgfx.starlingassets = new AssetManager();
+ dwgfx.starlingassets.enqueue(EmbeddedAssets);
+
+ Starling.current.nativeStage.scaleMode = StageScaleMode.NO_SCALE;
+ Starling.current.nativeStage.align = StageAlign.TOP_LEFT;
+ Starling.current.nativeStage.quality = StageQuality.LOW;
+
+ //TO DO: orientation code
+ game = new gameclass(dwgfx, map, obj, help, music);
- /*
- if (immersivemode) {
- stage.addEventListener(Event.RESIZE, androidresize);
- }
- */
- /*
- trace("NOTE: REMEMBER TO FIX RESOLUTION SUPPORT BEFORE BUILDING");
- device.xres = 1024;
- device.yres = 768;
- device.deviceresolution = device.IPAD;
- */
- //Testing:Let's be an ipad
- /*
- device.xres = 1024;
- device.yres = 768;
- device.deviceresolution = device.IPAD;
- */
- /*
- device.xres = 480;
- device.yres = 320;
- device.deviceresolution = device.IPHONE;
- */
- /*
- device.xres = 960;
- device.yres = 640;
- device.deviceresolution = device.IPHONE;
- */
-
- editor.init(); //Load in all the levels
-
- if (device.xres < device.yres) {
- //Switch them!
- t = device.yres;
- device.yres = device.xres;
- device.xres = t;
- }
-
- if (device.yres < 768) {
- device.deviceresolution = device.IPHONE;
- }else {
- device.deviceresolution = device.IPAD;
- }
-
- //Manually enable androids here! Mostly just changed buttons sizes
- // device.deviceresolution = device.ANDROID;
-
- //General game variables
- obj.init();
- help.init();
-
- /*obj.createblock(BLOCK,20,200,128,16);
- obj.createblock(BLOCK,130,170,128,16);
- obj.createblock(BLOCK,240,150,128,16);
- obj.createblock(BLOCK,240,20,128,16);
- obj.createblock(BLOCK,130,40,128,16);
- obj.createblock(BLOCK,20,60,128,16);*/
-
- //Input
- key.definestickrange(device.xres / 2, 0, 6);
-
- SoundMixer.soundTransform = new SoundTransform(1);
-
- music.currentsong = -1; music.musicfade = 0;//no music, no amb
- music.initefchannels(); music.currentefchan = 0;
- music.nicechange = -1;
-
- music.numplays = 0;
- music.musicchan.push(new music_1()); // 0: Level Complete
- music.musicchan.push(new vmaintheme_hq()); // 1: VVVVVV Main Theme (Pushing Forward)
- music.musicchan.push(new vtempo_hq()); // 2: VVVVVV Tempo Theme (Positive Force)
- music.musicchan.push(new vpfa_hq()); // 3: Potential for Anything
- music.musicchan.push(new passionforexploring()); // 4: UU Brothers Instrumental
- music.musicchan.push(new souleye_intermission()); // 5: Jingle: Intermission
- music.musicchan.push(new presentingvvvvvv()); // 6: Jingle: Menu Loop
- music.musicchan.push(new music_2()); // 7: Jingle: Game Complete
- music.musicchan.push(new configmegamix_hq()); // 8: Config Megamix
- music.musicchan.push(new posreverse()); // 9: Tempo Theme, Reversed
- music.musicchan.push(new poppot()); // 10: Extra
- music.musicchan.push(new pipedream_hq()); // 11: Highscore
- music.musicchan.push(new pressurecooker_hq()); // 12: Pressure Cooker
- music.musicchan.push(new pacedenergy()); // NEW 13: Paced Energy
- music.musicchan.push(new piercingthesky()); // NEW 14: Piercing the Sky
- music.musicchan.push(new predestinedfateremix()); // NEW 15: Predestined Fate Remix
-
- music.efchan.push(new ef_0());
- music.efchan.push(new ef_1());
- music.efchan.push(new ef_2());
- music.efchan.push(new ef_3());
- music.efchan.push(new ef_4());
- music.efchan.push(new ef_5());
- music.efchan.push(new ef_6());
- music.efchan.push(new ef_7());
- music.efchan.push(new ef_8());
- music.efchan.push(new ef_9());
- music.efchan.push(new ef_10());
- music.efchan.push(new ef_11());
- music.efchan.push(new ef_12());
- music.efchan.push(new ef_13());
- music.efchan.push(new ef_14());
- music.efchan.push(new ef_15());
- music.efchan.push(new ef_16());
- music.efchan.push(new ef_17());
- music.efchan.push(new ef_18());
- music.efchan.push(new ef_19());
- music.efchan.push(new ef_20());
- music.efchan.push(new ef_21());
- music.efchan.push(new ef_22());
- music.efchan.push(new ef_23());
- music.efchan.push(new ef_24());
- music.efchan.push(new ef_25());
- music.efchan.push(new ef_26());
- music.efchan.push(new ef_27());
-
- /*
- Graphics Init
- */
- //First we init the class and add its display list to the main display list
-
- dwgfx.buttonimg.push(new BitmapData(92, 30, true, 0x00000000));
- dwgfx.buttonimg.push(new BitmapData(92, 30, true, 0x00000000));
- dwgfx.buttonimg.push(new BitmapData(40, 40, true, 0x00000000));
- dwgfx.buttonimg.push(new BitmapData(40, 40, true, 0x00000000));
- tempbmp = new im_button_0(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_2(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_3(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_4(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_5(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_6(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_7(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_8(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_9(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_10(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_11(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
- tempbmp = new im_button_12(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addbutton();
-
- dwgfx.init();
-
- //We load all our graphics in:
- tempbmp = new im_tiles(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.maketilearray();
- tempbmp = new im_tiles2(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.maketile2array();
- tempbmp = new im_tiles3(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.maketile3array();
- tempbmp = new im_sprites(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makespritearray();
- tempbmp = new im_flipsprites(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makeflipspritearray();
- tempbmp = new im_bfont(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makebfont();
- tempbmp = new im_bfontmask(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makebfontmask();
- tempbmp = new im_teleporter(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.maketelearray();
- tempbmp = new im_entcolours(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makeentcolourarray();
- //Load in the images
- tempbmp = new im_image0(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 0
- tempbmp = new im_image1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 1 (this is the minimap!)
- tempbmp = new im_image2(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 2
- tempbmp = new im_image3(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 3
- tempbmp = new im_image4(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 4
- tempbmp = new im_image5(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 5
- tempbmp = new im_image6(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 6
- tempbmp = new im_image7(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 7
- tempbmp = new im_image8(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 8
- tempbmp = new im_image9(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 9
- tempbmp = new im_image10(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // 10
-
- tempbmp = new im_image1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // Minimap
- tempbmp = new im_image1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addimage(); // Minimap
-
- tempbmp = new im_mobileimage1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage2(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage3(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage4(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage5(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage6(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage7(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage8(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
- tempbmp = new im_mobileimage9(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addmobileimage();
-
- tempbmp = new im_imgplayerlevel0(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel1(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel2(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel3(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel4(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel5(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel6(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel7(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel8(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel9(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel10(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel11(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel12(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel13(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel14(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel15(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
- tempbmp = new im_imgplayerlevel16(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.addplayerlevelimage();
-
- //Now that the graphics are loaded, init the background buffer
- dwgfx.buffer=new BitmapData(320,240,false,0x000000);
-
- stage.scaleMode = StageScaleMode.NO_SCALE;
- stage.align = StageAlign.TOP_LEFT;
- stage.quality = StageQuality.LOW;
-
- //EXACT FIT
- dwgfx.screensizemultiplier = device.yres / 240;
- dwgfx.screen.width = 320 * dwgfx.screensizemultiplier;
- dwgfx.screen.height = device.yres;
-
- dwgfx.screen.x = (device.xres / 2) - (320 * dwgfx.screensizemultiplier / 2);
- dwgfx.screen.y = 0;
-
- dwgfx.initbuttonpositions();
-
- //PIXEL PERFECT
- /*
- dwgfx.screensizemultiplier = int(device.yres / 240);
- dwgfx.screen.width = 320 * dwgfx.screensizemultiplier;
- dwgfx.screen.height = 240 * dwgfx.screensizemultiplier;
-
- dwgfx.screenoffx = (device.xres / 2) - (320 * dwgfx.screensizemultiplier / 2);
- dwgfx.screenoffy = (device.yres / 2) - (240 * dwgfx.screensizemultiplier / 2);
- dwgfx.screen.x = dwgfx.screenoffx;
- dwgfx.screen.y = dwgfx.screenoffy;
- */
-
- addChild(dwgfx);
- //stage.addChild(new TheMiner()); //Profiler
-
-
- //Iphone orientation fix
- var startOrientation:String = stage.orientation;
- if (startOrientation == StageOrientation.DEFAULT || startOrientation == StageOrientation.UPSIDE_DOWN){
- //stage.setOrientation(StageOrientation.ROTATED_RIGHT);
- stage.setAspectRatio(StageAspectRatio.LANDSCAPE);
- }else{
- stage.setOrientation(startOrientation);
- }
- stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChangeListener);
-
- game = new gameclass(dwgfx, map, obj, help, music);
-
-
- map.ypos = (700-29) * 8;
- map.bypos = map.ypos / 2;
- map.cameramode = 0;
-
-
- ///Test Start:
- //-- Comment this for real start
- /*
- gamestate = GAMEMODE;
- /*map.finalmode = true; //Enable final level mode
- //map.finalx = 41; map.finaly = 52; //Midpoint
- //map.finalx = 48; map.finaly = 52; //Just before the tower
+ map.ypos = (700-29) * 8;
+ map.bypos = map.ypos / 2;
+ map.cameramode = 0;
+
+
+ ///Test Start:
+ //-- Comment this for real start
+ /*
+ gamestate = GAMEMODE;
+ /*map.finalmode = true; //Enable final level mode
+ //map.finalx = 41; map.finaly = 52; //Midpoint
+ //map.finalx = 48; map.finaly = 52; //Just before the tower
+ map.finalx = 46; map.finaly = 54; //Current
+ //map.finalstretch = true;
+ map.final_colormode = true;
+ map.final_mapcol = 0;
+ map.final_colorframe = 0;
+ */
+ /*
+ game.starttest(obj, music);
+ obj.createentity(game, game.savex, game.savey, 0); //In this game, constant, never destroyed
+ map.gotoroom(game.saverx, game.savery, dwgfx, game, obj, music);
+ music.play(1);
+ */
+ //game.crewstats[1] = true;
+ //game.crewstats[2] = true;
+ //game.crewstats[3] = true;
+ //game.crewstats[4] = true;
+ //game.crewstats[5] = true;
+ //script.load("intro");
+
+ //crew member test
+ //obj.createentity(game, game.savex - 10, game.savey - 10, 14);
+ //game.companion = 6; //different rules for different members
+
+
+
+ //--
+ //Uncomment this if testing the final level
+ /*
+ map.finalmode = true; //Enable final level mode
map.finalx = 46; map.finaly = 54; //Current
- //map.finalstretch = true;
+ //map.finalx = 41; map.finaly = 52; //Midpoint
+ map.final_colormode = false; map.final_mapcol = 0; map.final_colorframe = 0;
+ */
+ //And this if after the midpoint:
+ /*
+ map.finalx = 52; map.finaly = 53; //Current
+ map.finalstretch = true;
map.final_colormode = true;
map.final_mapcol = 0;
map.final_colorframe = 0;
- */
- /*
- game.starttest(obj, music);
- obj.createentity(game, game.savex, game.savey, 0); //In this game, constant, never destroyed
- map.gotoroom(game.saverx, game.savery, dwgfx, game, obj, music);
- music.play(1);
- */
- //game.crewstats[1] = true;
- //game.crewstats[2] = true;
- //game.crewstats[3] = true;
- //game.crewstats[4] = true;
- //game.crewstats[5] = true;
- //script.load("intro");
-
- //crew member test
- //obj.createentity(game, game.savex - 10, game.savey - 10, 14);
- //game.companion = 6; //different rules for different members
-
-
-
- //--
- //Uncomment this if testing the final level
- /*
- map.finalmode = true; //Enable final level mode
- map.finalx = 46; map.finaly = 54; //Current
- //map.finalx = 41; map.finaly = 52; //Midpoint
- map.final_colormode = false; map.final_mapcol = 0; map.final_colorframe = 0;
- */
- //And this if after the midpoint:
- /*
- map.finalx = 52; map.finaly = 53; //Current
- map.finalstretch = true;
- map.final_colormode = true;
- map.final_mapcol = 0;
- map.final_colorframe = 0;
- //map.background = 6;
- */
- //-- Jumping right in
- /*
- game.gamestate = GAMEMODE;
- game.starttest(obj, music);
- //game.loadquick(map, obj, music);
- obj.createentity(game, game.savex, game.savey, 0); //In this game, constant, never destroyed
- map.gotoroom(game.saverx, game.savery, dwgfx, game, obj, music);
- music.play(4);
- //fscommand("quit");
-
- game.crewstats[1] = true;
- //game.crewstats[2] = true;
- game.crewstats[3] = true;
- game.crewstats[4] = true;
- //game.crewstats[5] = true;
-
- map.showtargets = true;
- map.showteleporters = true;
- //map.showtrinkets = true;
-
- //obj.flags[34] = 1;
- //obj.flags[20] = 1;
- //obj.flags[67] = 1; //Game complete
+ //map.background = 6;
+ */
+ //-- Jumping right in
+ /*
+ game.gamestate = GAMEMODE;
+ game.starttest(obj, music);
+ //game.loadquick(map, obj, music);
+ obj.createentity(game, game.savex, game.savey, 0); //In this game, constant, never destroyed
+ map.gotoroom(game.saverx, game.savery, dwgfx, game, obj, music);
+ music.play(4);
+ //fscommand("quit");
+
+ game.crewstats[1] = true;
+ //game.crewstats[2] = true;
+ game.crewstats[3] = true;
+ game.crewstats[4] = true;
+ //game.crewstats[5] = true;
+
+ map.showtargets = true;
+ map.showteleporters = true;
+ //map.showtrinkets = true;
+
+ //obj.flags[34] = 1;
+ //obj.flags[20] = 1;
+ //obj.flags[67] = 1; //Game complete
+ for (i = 0; i < 20; i++) {
+ obj.collect[i] = true;
+ }
+ game.trinkets = 19; obj.collect[18] = false;
+ game.stat_trinkets = 20;
+ //obj.altstates = 1;
+
+ //initilise map info
+ for (j = 0; j < 20; j++) {
for (i = 0; i < 20; i++) {
- obj.collect[i] = true;
+ map.explored[i + (j * 20)] = 1;
}
- game.trinkets = 19; obj.collect[18] = false;
- game.stat_trinkets = 20;
- //obj.altstates = 1;
-
- //initilise map info
- for (j = 0; j < 20; j++) {
- for (i = 0; i < 20; i++) {
- map.explored[i + (j * 20)] = 1;
- }
- }
- */
- //obj.entities[obj.getplayer()].size = 13;
-
- //game.gamestate = 6;
-
- //game.intimetrail = true; game.timetrialcountdown = 0;
- //game.nodeathmode = true;
- //dwgfx.flipmode = true;
- //game.nocutscenes = true;
- //map.invincibility = true;
- //stage.frameRate = 24;
- //game.colourblindmode = true;
- //game.noflashingmode = true;
- //for intermission 2 test
- //game.lastsaved = 3;
- /*
- game.swnmode = true;
- game.swngame = 2;
- game.swndelay = 120;
- game.swntimer = 60 * 30;
- */
- //script.load("intermission_2");
-
-
- //for intermission 1 test
- /*
- game.companion = 11;
- game.supercrewmate = true;
- game.scmprogress = 0;
- game.scmprogress = 10;
- game.lastsaved = 4;
- music.play(8);
- */
- //game.sfpsmode = true; //Run at 60 FPS
- //stage.frameRate = 60; // doesn't work, it's a bit more complex than this - will have to do a double sized window instead...
-
- //dwgfx.flipmode = true;
-
- //Testing some unlock stuff
- /*
- game.unlock[9] = true; //Space Station Intro Time Trial
- game.unlock[10] = true; //Lab Time Trial
- game.unlock[11] = true; //Tower Time Trial
- game.unlock[12] = true; //Space Station 2 Time Trial
- game.unlock[13] = true; //Warp Zone Time Trial
- game.unlock[14] = true; //Final Level Time Trial
-
- game.unlock[17] = true; //No death mode
- game.unlock[18] = true; //Flip Mode
-
- */
- //-- Normal start, with no fancy stuff!
-
- /*
- game.gamestate = CLICKTOSTART;
- dwgfx.createtextbox(" Click to Start ", 96, 107, 164, 164, 255);
- dwgfx.textboxcenter();
- */
- //No click to start any more! Instead go right to the menu
-
- //INIT GRAPHIC MODE HERE
- game.loadstats(map, dwgfx);
-
- //updategraphicsmode(game, dwgfx);
-
- game.gamestate = TITLEMODE;
-
- game.menustart = false;
- game.mainmenu = 0;
-
- /*if (game.quicksummary != "") {
- game.mainmenu = 2;
- }
- if (game.telesummary != "") {
- game.mainmenu = 1;
- }*/ //what the hell is that for
-
-
- /*
- game.gamestate = 6;
- game.menustart = true;
- map.ypos = (700-29) * 8;
- map.bypos = map.ypos / 2;
- map.cameramode = 0;
- */
- //--Everything after this is screen recording
-
- //ok, screenrecording here
- //don't record anything (comment both next parts)
-
- game.recording = 0;
-
- if(game.recording==1){
- trace("warning! recording input!");
- }else if(game.recording==2){
- trace("playing back input!");
- game.recordstring = "blahblahblah";
- help.toclipboard(game.recordstring);
-
- game.initplayback();
- game.playbackpos = 5;
- game.savex = game.playback[0]; game.savey = game.playback[1];
- game.saverx = game.playback[2]; game.savery = game.playback[3];
- game.savegc = game.playback[4]; game.savedir = 1;
- }
-
- //addEventListener(Event.ENTER_FRAME, mainloop);
-
- // start the tick-timer, which updates roughly every 4 milliseconds
- _timer.addEventListener(TimerEvent.TIMER, mainloop);
- _timer.start();
- }else {
- dwgfx.init();
- addChild(dwgfx);
- //We load the font in:
- tempbmp = new im_bfont(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makebfont();
- tempbmp = new im_bfontmask(); dwgfx.buffer = tempbmp.bitmapData; dwgfx.makebfontmask();
- //Now that the graphics are loaded, init the background buffer
- dwgfx.buffer = new BitmapData(320, 240, false, 0x000000);
-
- addEventListener(Event.ENTER_FRAME, lockedloop);
}
- }
-
- public function visit_distractionware(e:Event):void{
- var distractionware_link:URLRequest = new URLRequest( "http://www.distractionware.com" );
- navigateToURL( distractionware_link, "_blank" );
- }
-
- public function visit_sponsor(e:Event):void{
- var sponsor_link:URLRequest = new URLRequest( "http://www.kongregate.com/?gamereferral=dontlookback" );
- navigateToURL( sponsor_link, "_blank" );
- }
-
- public function visit_sponsor_logo():void{
- var sponsor_link:URLRequest = new URLRequest( "http://www.kongregate.com/?gamereferral=dontlookback" );
- navigateToURL( sponsor_link, "_blank" );
- }
-
- /*
- public function androidresize(e:Event):void {
- if (immersivemode) {
- device.xres = stage.stageWidth;
- device.yres = stage.stageHeight;
- }else{
- device.xres = flash.system.Capabilities.screenResolutionX;
- device.yres = flash.system.Capabilities.screenResolutionY;
+ */
+ //obj.entities[obj.getplayer()].size = 13;
+
+ //game.gamestate = 6;
+
+ //game.intimetrail = true; game.timetrialcountdown = 0;
+ //game.nodeathmode = true;
+ //dwgfx.flipmode = true;
+ //game.nocutscenes = true;
+ //map.invincibility = true;
+ //stage.frameRate = 24;
+ //game.colourblindmode = true;
+ //game.noflashingmode = true;
+ //for intermission 2 test
+ //game.lastsaved = 3;
+ /*
+ game.swnmode = true;
+ game.swngame = 2;
+ game.swndelay = 120;
+ game.swntimer = 60 * 30;
+ */
+ //script.load("intermission_2");
+
+
+ //for intermission 1 test
+ /*
+ game.companion = 11;
+ game.supercrewmate = true;
+ game.scmprogress = 0;
+ game.scmprogress = 10;
+ game.lastsaved = 4;
+ music.play(8);
+ */
+ //game.sfpsmode = true; //Run at 60 FPS
+ //stage.frameRate = 60; // doesn't work, it's a bit more complex than this - will have to do a double sized window instead...
+
+ //dwgfx.flipmode = true;
+
+ //Testing some unlock stuff
+ /*
+ game.unlock[9] = true; //Space Station Intro Time Trial
+ game.unlock[10] = true; //Lab Time Trial
+ game.unlock[11] = true; //Tower Time Trial
+ game.unlock[12] = true; //Space Station 2 Time Trial
+ game.unlock[13] = true; //Warp Zone Time Trial
+ game.unlock[14] = true; //Final Level Time Trial
+
+ game.unlock[17] = true; //No death mode
+ game.unlock[18] = true; //Flip Mode
+
+ */
+ //-- Normal start, with no fancy stuff!
+
+ /*
+ game.gamestate = CLICKTOSTART;
+ dwgfx.createtextbox(" Click to Start ", 96, 107, 164, 164, 255);
+ dwgfx.textboxcenter();
+ */
+ //No click to start any more! Instead go right to the menu
+
+ //INIT GRAPHIC MODE HERE
+ game.loadstats(map, dwgfx);
+ //updategraphicsmode(game, dwgfx);
+
+ game.gamestate = TITLEMODE;
+
+ game.menustart = false;
+ game.mainmenu = 0;
+
+ /*if (game.quicksummary != "") {
+ game.mainmenu = 2;
}
- if (device.xres < device.yres) {
- //Switch them!
- t = device.yres;
- device.yres = device.xres;
- device.xres = t;
+ if (game.telesummary != "") {
+ game.mainmenu = 1;
+ }*/ //what the hell is that for
+
+
+ /*
+ game.gamestate = 6;
+ game.menustart = true;
+ map.ypos = (700-29) * 8;
+ map.bypos = map.ypos / 2;
+ map.cameramode = 0;
+ */
+ //--Everything after this is screen recording
+
+ //ok, screenrecording here
+ //don't record anything (comment both next parts)
+
+ game.recording = 0;
+
+ if(game.recording==1){
+ trace("warning! recording input!");
+ }else if(game.recording==2){
+ trace("playing back input!");
+ game.recordstring = "blahblahblah";
+ help.toclipboard(game.recordstring);
+
+ game.initplayback();
+ game.playbackpos = 5;
+ game.savex = game.playback[0]; game.savey = game.playback[1];
+ game.saverx = game.playback[2]; game.savery = game.playback[3];
+ game.savegc = game.playback[4]; game.savedir = 1;
}
- key.definestickrange(device.xres / 2, 0, 6);
+ //addEventListener(Event.ENTER_FRAME, mainloop);
- dwgfx.screensizemultiplier = device.yres / 240;
- dwgfx.screen.width = 320 * dwgfx.screensizemultiplier;
- dwgfx.screen.height = device.yres;
-
- dwgfx.screen.x = (device.xres / 2) - (320 * dwgfx.screensizemultiplier / 2);
- dwgfx.screen.y = 0;
-
- dwgfx.initbuttonpositions();
- }
- */
-
- public function orientationChangeListener(e:StageOrientationEvent):void{
- if (e.afterOrientation == StageOrientation.DEFAULT || e.afterOrientation == StageOrientation.UPSIDE_DOWN) {
- e.preventDefault();
- }
- }
-
- public function lockedloop(e:Event):void {
- dwgfx.backbuffer.lock();
-
- dwgfx.bprint(5, 110, "Sorry! This game can only be", 196-help.glow, 196-help.glow, 255-help.glow, true);
- dwgfx.bprint(5, 120, "played on thelettervsixtim.es", 196-help.glow, 196-help.glow, 255-help.glow, true);
- dwgfx.render();
- dwgfx.backbuffer.unlock();
-
- help.updateglow();
+ dwgfx.starlingassets.loadQueue(function(ratio:Number):void {
+ trace(ratio);
+ if (ratio == 1){
+ waitforassetstoload();
+ }
+ });
}
- public function setstage(w:int, h:int):void {
- //stage.stageWidth = w;
- //stage.stageHeight = h;
+ public function waitforassetstoload():void {
+ //Wait till this has loaded the texture before processing
+ dwgfx.button_texture.push(new RenderTexture(92, 30));
+ dwgfx.button_texture.push(new RenderTexture(92, 30));
+ dwgfx.button_texture.push(new RenderTexture(40, 40));
+ dwgfx.button_texture.push(new RenderTexture(40, 40));
+ dwgfx.addbutton("mobilebuttons/map");
+ dwgfx.addbutton("mobilebuttons/back");
+ dwgfx.addbutton("mobilebuttons/talk_1");
+ dwgfx.addbutton("mobilebuttons/talk_2");
+ dwgfx.addbutton("mobilebuttons/use_1");
+ dwgfx.addbutton("mobilebuttons/use_2");
+ dwgfx.addbutton("mobilebuttons/teleport_1");
+ dwgfx.addbutton("mobilebuttons/teleport_2");
+ dwgfx.addbutton("mobilebuttons/controls_1");
+ dwgfx.addbutton("mobilebuttons/controls_2");
+ dwgfx.addbutton("mobilebuttons/gamecenter");
+ dwgfx.addbutton("mobilebuttons/button_left");
+ dwgfx.addbutton("mobilebuttons/button_right");
+ dwgfx.initbuttonstuff();
+
+ //We load all our graphics in:
+ dwgfx.maketilearray();
+ dwgfx.maketile2array();
+ dwgfx.maketile3array();
+ dwgfx.makespritearray();
+ dwgfx.makeflipspritearray();
+ dwgfx.maketelearray();
+ dwgfx.makeentcolourarray();
+
+ //Load in the images
+ dwgfx.addimage("levelcomplete"); // 0
+ dwgfx.addimage("minimap"); // 1 (this is the minimap!)
+ dwgfx.addimage("covered"); // 2
+ dwgfx.addimage("elephant"); // 3
+ dwgfx.addimage("gamecomplete"); // 4
+ dwgfx.addimage("fliplevelcomplete"); // 5
+ dwgfx.addimage("flipgamecomplete"); // 6
+ dwgfx.addimage("site"); // 7
+ dwgfx.addimage("site2"); // 8
+ dwgfx.addimage("site3"); // 9
+ dwgfx.addimage("ending"); // 10
+
+ dwgfx.addimage("minimap"); // Minimap
+ dwgfx.addimage_rendertexture("minimap"); // Minimap
+
+ dwgfx.addmobileimage("controls/touchscreen");
+ dwgfx.addmobileimage("controls/lefthand_off");
+ dwgfx.addmobileimage("controls/lefthand_near");
+ dwgfx.addmobileimage("controls/lefthand_far");
+ dwgfx.addmobileimage("controls/righthand_off");
+ dwgfx.addmobileimage("controls/righthand_near");
+ dwgfx.addmobileimage("controls/righthand_far");
+ dwgfx.addmobileimage("controls/arrowleft");
+ dwgfx.addmobileimage("controls/arrowright");
+
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_0");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_1");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_2");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_3");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_4");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_5");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_6");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_7");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_8");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_9");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_10");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_11");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_12");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_13");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_14");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_15");
+ dwgfx.addplayerlevelimage("playerlevels/playerlevel_16");
+
+ var c64fontbm:BitmapFont = new BitmapFont(dwgfx.starlingassets.getTexture("c64/c64_0"),
+ XML(new c64font_xml));
+ TextField.registerCompositor(c64fontbm, "c64");
+
+ _timer.addEventListener(TimerEvent.TIMER, mainloop);
+ _timer.start();
+
+ androidresize();
}
public function sitelock():Boolean {
- //No preloader for Kong version
- var currUrl:String = stage.loaderInfo.url.toLowerCase();
- //chat.kongregate.com
- if ((currUrl.indexOf("ile:///") <= 0) || (currUrl.indexOf("http") == 0)){
- //if ((currUrl.indexOf("distractionware.com/games") <= 0) && (currUrl.indexOf("thelettervsixtim.es/secretarea") <= 0)){
- return true;
- //return false;
- }else{
- return true;
- }
+ //we don't care about this on mobile
+ return true;
}
public function input():void {
@@ -741,9 +574,9 @@
if (game.platform.wakeupcall > 0) {
game.platform.wakeupcall--;
if (game.platform.wakeupcall == 0) {
- if(immersivemode){
- //AndroidFullScreen.immersiveMode();
- }
+ //if(immersivemode){
+ // AndroidFullScreen.immersiveMode();
+ //}
}
}
@@ -768,52 +601,54 @@
}
}
- public function render():void {
- if (!game.infocus) {
- dwgfx.backbuffer.lock();
- /*
- dwgfx.bprint(5, 110, "Game paused", 196 - help.glow, 255 - help.glow, 196 - help.glow, true);
- dwgfx.bprint(5, 120, "[click to resume]", 196 - help.glow, 255 - help.glow, 196 - help.glow, true);
- dwgfx.bprint(5, 230, "Press M to mute in game", 164 - help.glow, 196 - help.glow, 164 - help.glow, true);
- */
- dwgfx.render();
- dwgfx.backbuffer.unlock();
- }else {
- switch(game.gamestate){
- case TITLEMODE:
- titlerender(key, dwgfx, map, game, obj, help);
- break;
- case GAMEMODE:
- if (map.towermode) {
- towerrender(key, dwgfx, game, map, obj, help);
- }else{
- gamerender(key, dwgfx, game, map, obj, help);
- }
- break;
- case CONTROLTUTORIALMODE:
- controltutorialrender(key, dwgfx, game, map, obj, help);
- break;
- case MAPMODE:
- maprender(key, dwgfx, game, map, obj, help);
- break;
- case TELEPORTERMODE:
- teleporterrender(key, dwgfx, game, map, obj, help);
- break;
- case GAMECOMPLETE:
- gamecompleterender(key, dwgfx, game, obj, help);
- break;
- case GAMECOMPLETE2:
- gamecompleterender2(key, dwgfx, game, obj, help);
- break;
- case CLICKTOSTART:
- dwgfx.backbuffer.lock();
- //dwgfx.bprint(5, 115, "[Click to start]", 196 - help.glow, 196 - help.glow, 255 - help.glow, true);
- dwgfx.drawgui(help);
- dwgfx.render();
- dwgfx.backbuffer.unlock();
- break;
+ public function dorender():void {
+ dwgfx.backbuffer.drawBundled(function():void {
+ if (!game.infocus) {
+ //dwgfx.backbuffer.lock();
+ /*
+ dwgfx.bprint(5, 110, "Game paused", 196 - help.glow, 255 - help.glow, 196 - help.glow, true);
+ dwgfx.bprint(5, 120, "[click to resume]", 196 - help.glow, 255 - help.glow, 196 - help.glow, true);
+ dwgfx.bprint(5, 230, "Press M to mute in game", 164 - help.glow, 196 - help.glow, 164 - help.glow, true);
+ */
+ dwgfx.render();
+ //dwgfx.backbuffer.unlock();
+ }else {
+ switch(game.gamestate){
+ case TITLEMODE:
+ titlerender(key, dwgfx, map, game, obj, help);
+ break;
+ case GAMEMODE:
+ if (map.towermode) {
+ towerrender(key, dwgfx, game, map, obj, help);
+ }else{
+ gamerender(key, dwgfx, game, map, obj, help);
+ }
+ break;
+ case CONTROLTUTORIALMODE:
+ controltutorialrender(key, dwgfx, game, map, obj, help);
+ break;
+ case MAPMODE:
+ maprender(key, dwgfx, game, map, obj, help);
+ break;
+ case TELEPORTERMODE:
+ teleporterrender(key, dwgfx, game, map, obj, help);
+ break;
+ case GAMECOMPLETE:
+ gamecompleterender(key, dwgfx, game, map, obj, help);
+ break;
+ case GAMECOMPLETE2:
+ gamecompleterender2(key, dwgfx, game, obj, help);
+ break;
+ case CLICKTOSTART:
+ //dwgfx.backbuffer.lock();
+ //dwgfx.bprint(5, 115, "[Click to start]", 196 - help.glow, 196 - help.glow, 255 - help.glow, true);
+ dwgfx.drawgui(help);
+ dwgfx.render();
+ //dwgfx.backbuffer.unlock();
+ break;
+ }
}
- }
+ });
}
public function mainloop(e:TimerEvent):void {
@@ -829,82 +664,45 @@
logic();
if (key.hasclicked) key.click = false;
}
- render();
+ dorender();
e.updateAfterEvent();
}
}
- public function setzoom(t:int, dwgfx:dwgraphicsclass):void {
- /*
- switch(t) {
- case 1:
- dwgfx.screen.width = 320;
- dwgfx.screen.height = 240;
- dwgfx.screen.x = (640 - 320) / 2;
- dwgfx.screen.y = (480 - 240) / 2;
- break;
- case 2:
- dwgfx.screen.width = 640;
- dwgfx.screen.height = 480;
- dwgfx.screen.x = 0;
- dwgfx.screen.y = 0;
- break;
- case 3:
- dwgfx.screen.width = 960;
- dwgfx.screen.height = 720;
- dwgfx.screen.x = (640 - 960) / 2;
- dwgfx.screen.y = (480 - 720) / 2;
- break;
- case 4:
- dwgfx.screen.width = 1280;
- dwgfx.screen.height = 960;
- dwgfx.screen.x = (640 - 1280) / 2;
- dwgfx.screen.y = (480 - 960) / 2;
- break;
- }
- */
+ public function androidresize():void {
+ /*if(immersivemode){
+ AndroidFullScreen.stage = Starling.current.nativeStage; // Set this to your app's stage
+ AndroidFullScreen.fullScreen();
+
+ device.xres = AndroidFullScreen.immersiveWidth;
+ device.yres = AndroidFullScreen.immersiveHeight;
+ }else {*/
+ Starling.current.nativeStage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
+ if(!device.localtesting){
+ //device.xres = flash.system.Capabilities.screenResolutionX;
+ //device.yres = flash.system.Capabilities.screenResolutionY;
+ device.xres = Screen.mainScreen.safeArea.width;
+ device.yres = Screen.mainScreen.safeArea.height;
+ }else{
+ device.xres = 1280;
+ device.yres = 800;
+ }
+ //}
+
+ if (device.xres < device.yres) {
+ //Switch them!
+ var t:int = device.yres;
+ device.yres = device.xres;
+ device.xres = t;
+ }
+ key.definestickrange(device.xres / 2, 0, 6);
+
+ dwgfx.updatescreen(device.xres, device.yres);
+ if(dwgfx.buttonsready) dwgfx.initbuttonpositions();
}
public function updategraphicsmode(game:gameclass, dwgfx:dwgraphicsclass):void {
- /*
- swfStage = stage;
-
- if (game.advanced_mode) { //advanced graphics mode
- //Screen Smooting
- dwgfx.screen.smoothing = game.advanced_smoothing;
-
- //Scaling
- if(game.advanced_scaling==0){
- swfStage.scaleMode = StageScaleMode.SHOW_ALL;
- setzoom(2, dwgfx);
- }else{
- swfStage.scaleMode = StageScaleMode.NO_SCALE; //Turn Scaling off
- setzoom(game.advanced_scaling, dwgfx);
- }
-
- stage.fullScreenSourceRect = null;
- //Fullscreen
- if (game.fullscreen) {
- stage.displayState = StageDisplayState.FULL_SCREEN;
- Mouse.hide();
- }else {
- stage.displayState = StageDisplayState.NORMAL;
- Mouse.show();
- }
- }else{
- swfStage.scaleMode = StageScaleMode.SHOW_ALL;
- if (game.fullscreen) {
- dwgfx.screen.smoothing = true;
- stage.fullScreenSourceRect = new Rectangle(0, 0, 640, 480);
- stage.displayState = StageDisplayState.FULL_SCREEN;
- Mouse.hide();
- }else {
- dwgfx.screen.smoothing = false;
- stage.displayState = StageDisplayState.NORMAL;
- Mouse.show();
- }
- }
- */
+ //ghost of a function that once was
}
// Timer information (a shout out to ChevyRay for the implementation)
@@ -916,6 +714,7 @@
private var _delta:Number = 0;
private var _timer:Timer = new Timer(4);
+
public var dwgfx:dwgraphicsclass = new dwgraphicsclass();
public var music:musicclass = new musicclass();
public var help:helpclass = new helpclass();
@@ -932,75 +731,12 @@
public var i:int, j:int, k:int, temp:int, tempx:int, tempy:int, tempstring:String;
public var tr:int, tg:int, tb:int, t:int;
public var tvel:Number;
- public var swfStage:Stage;
public var immersivemode:Boolean;
- //Embedded resources:
- //Graphics
- [Embed(source = '../data/graphics/tiles.png')] private var im_tiles:Class;
- [Embed(source = '../data/graphics/tiles2.png')] private var im_tiles2:Class;
- [Embed(source = '../data/graphics/tiles3.png')] private var im_tiles3:Class;
- [Embed(source = '../data/graphics/sprites.png')] private var im_sprites:Class;
- [Embed(source = '../data/graphics/flipsprites.png')] private var im_flipsprites:Class;
- [Embed(source = '../data/graphics/font.png')] private var im_bfont:Class;
- [Embed(source = '../data/graphics/fontmask.png')] private var im_bfontmask:Class;
- [Embed(source = '../data/graphics/teleporter.png')] private var im_teleporter:Class;
- [Embed(source = '../data/graphics/entcolours.png')] private var im_entcolours:Class;
- [Embed(source = '../data/graphics/levelcomplete.png')] private var im_image0:Class;
- [Embed(source = '../data/graphics/minimap.png')] private var im_image1:Class;
- [Embed(source = '../data/graphics/covered.png')] private var im_image2:Class;
- [Embed(source = '../data/graphics/elephant.png')] private var im_image3:Class;
- [Embed(source = '../data/graphics/gamecomplete.png')] private var im_image4:Class;
- [Embed(source = '../data/graphics/fliplevelcomplete.png')] private var im_image5:Class;
- [Embed(source = '../data/graphics/flipgamecomplete.png')] private var im_image6:Class;
- [Embed(source = '../data/graphics/site.png')] private var im_image7:Class;
- [Embed(source = '../data/graphics/site2.png')] private var im_image8:Class;
- [Embed(source = '../data/graphics/site3.png')] private var im_image9:Class;
- [Embed(source = '../data/graphics/ending.png')] private var im_image10:Class;
+ [Embed(source="../data/c64.fnt", mimeType="application/octet-stream")]
+ public static const c64font_xml:Class;
- [Embed(source = '../data/graphics/controls/touchscreen.png')] private var im_mobileimage1:Class;
- [Embed(source = '../data/graphics/controls/lefthand_off.png')] private var im_mobileimage2:Class;
- [Embed(source = '../data/graphics/controls/lefthand_near.png')] private var im_mobileimage3:Class;
- [Embed(source = '../data/graphics/controls/lefthand_far.png')] private var im_mobileimage4:Class;
- [Embed(source = '../data/graphics/controls/righthand_off.png')] private var im_mobileimage5:Class;
- [Embed(source = '../data/graphics/controls/righthand_near.png')] private var im_mobileimage6:Class;
- [Embed(source = '../data/graphics/controls/righthand_far.png')] private var im_mobileimage7:Class;
- [Embed(source = '../data/graphics/controls/arrowleft.png')] private var im_mobileimage8:Class;
- [Embed(source = '../data/graphics/controls/arrowright.png')] private var im_mobileimage9:Class;
- //Playerlevel images
- [Embed(source = '../data/graphics/playerlevels/playerlevel_0.png')] private var im_imgplayerlevel0:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_1.png')] private var im_imgplayerlevel1:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_2.png')] private var im_imgplayerlevel2:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_3.png')] private var im_imgplayerlevel3:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_4.png')] private var im_imgplayerlevel4:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_5.png')] private var im_imgplayerlevel5:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_6.png')] private var im_imgplayerlevel6:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_7.png')] private var im_imgplayerlevel7:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_8.png')] private var im_imgplayerlevel8:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_9.png')] private var im_imgplayerlevel9:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_10.png')] private var im_imgplayerlevel10:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_11.png')] private var im_imgplayerlevel11:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_12.png')] private var im_imgplayerlevel12:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_13.png')] private var im_imgplayerlevel13:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_14.png')] private var im_imgplayerlevel14:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_15.png')] private var im_imgplayerlevel15:Class;
- [Embed(source = '../data/graphics/playerlevels/playerlevel_16.png')] private var im_imgplayerlevel16:Class;
- //iOS Buttons
- [Embed(source = '../data/graphics/mobilebuttons/map.png')] private var im_button_0:Class;
- [Embed(source = '../data/graphics/mobilebuttons/back.png')] private var im_button_1:Class;
- [Embed(source = '../data/graphics/mobilebuttons/talk_1.png')] private var im_button_2:Class;
- [Embed(source = '../data/graphics/mobilebuttons/talk_2.png')] private var im_button_3:Class;
- [Embed(source = '../data/graphics/mobilebuttons/use_1.png')] private var im_button_4:Class;
- [Embed(source = '../data/graphics/mobilebuttons/use_2.png')] private var im_button_5:Class;
- [Embed(source = '../data/graphics/mobilebuttons/teleport_1.png')] private var im_button_6:Class;
- [Embed(source = '../data/graphics/mobilebuttons/teleport_2.png')] private var im_button_7:Class;
- [Embed(source = '../data/graphics/mobilebuttons/controls_1.png')] private var im_button_8:Class;
- [Embed(source = '../data/graphics/mobilebuttons/controls_2.png')] private var im_button_9:Class;
- [Embed(source = '../data/graphics/mobilebuttons/gamecenter.png')] private var im_button_10:Class;
- [Embed(source = '../data/graphics/mobilebuttons/button_left.png')] private var im_button_11:Class;
- [Embed(source = '../data/graphics/mobilebuttons/button_right.png')] private var im_button_12:Class;
-
- //Music
+ //Music
[Embed(source = '../data/music/levelcomplete.mp3')] private var music_1:Class;
[Embed(source = '../data/music/endgame.mp3')] private var music_2:Class;
//Sound effects
@@ -1033,4 +769,4 @@
[Embed(source = '../data/sounds/trophy.mp3')] private var ef_26:Class;
[Embed(source = '../data/sounds/rescue.mp3')] private var ef_27:Class;
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/mobile_version/src/Preloader.as b/mobile_version/src/Preloader.as
deleted file mode 100644
index 286678d1..00000000
--- a/mobile_version/src/Preloader.as
+++ /dev/null
@@ -1,310 +0,0 @@
-//Big thanks to Muku for his help with working out how to do a preloader in FlashDevelop!
-
-package {
- import flash.display.*;
- import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
- import flash.utils.getDefinitionByName;
- import flash.system.fscommand;
- import flash.ui.ContextMenu;
- import flash.ui.ContextMenuItem;
- //import com.kongregate.as3.client.KongregateAPI;
-
- //Mochi and Kongregate stuff is more or less ready here
-
- public dynamic class Preloader extends MovieClip {
- public function Preloader() {
- fscommand("trapallkeys", "true");
- if (stage.root.loaderInfo.url.search(/.swf$/) >= 0) {
- //fscommand("showmenu", "false");
- }
- stage.showDefaultContextMenu = (stage.root.loaderInfo.url.search(/.swf$/) >= 0);
-
- //For the offline version, manually change this
- if (checksite()) {
- adson = false;
- }else{
- adson = true;
- }
- adson = false;
-
- //Let's assume the kong API is clever enough to do its own checking
- //var kongregate:KongregateAPI = new KongregateAPI();
- //this.addChild ( kongregate );
-
- //stage.showDefaultContextMenu = false;
-
-
- //show c64 intro (30, 0), set to (-10, 100) to not show
- //transition = -10; fakepercent = 100;
- transition = 30; fakepercent = 0;
-
-
- var rc_menu:ContextMenu = new ContextMenu();
- rc_menu.hideBuiltInItems();
- this.contextMenu = rc_menu;
- ct = new ColorTransform(0, 0, 0, 1, 255, 255, 255, 1); //Set to white
-
- darkcol = 0x000000; lightcol = 0x000000; curcol = 0;
- offset = 0; coltimer = 0;
-
- frontrect = new Rectangle(30, 20, 260, 200);
- temprect = new Rectangle(0, 0, 320, 24);
-
- tl = new Point(0, 0);
- tpoint = new Point(0, 0);
- bfont_rect=new Rectangle(0,0,8,8);
- var tempbmp:Bitmap;
- tempbmp = new im_bfont(); buffer = tempbmp.bitmapData;
- makebfont();
-
- backbuffer=new BitmapData(320, 240,false,0x000000);
- screenbuffer = new BitmapData(320, 240, false, 0x000000);
- screen = new Bitmap(screenbuffer);
- screen.width = 640;//320;//;640;
- screen.height = 480;// 240;//480;
-
- addChild(screen);
-
- addEventListener(Event.ENTER_FRAME, checkFrame);
-
- if (!adson) {
- /*
- loading = new im_loading();
- loading.x = 320 - (loading.width / 2);
- loading.y = 316;
- addChild(loading);
- */
- }
-
- showctp = false;
- startgame = false;
- }
-
- public function visit_distractionware(e:Event):void{
- var distractionware_link:URLRequest = new URLRequest( "http://www.distractionware.com" );
- navigateToURL( distractionware_link, "_blank" );
- }
-
- public function visit_sponsor(e:Event):void{
- var sponsor_link:URLRequest = new URLRequest( "http://www.kongregate.com/?gamereferral=dontlookback" );
- navigateToURL( sponsor_link, "_blank" );
- }
-
- public function print(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
- if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
- if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if (cen) x = x - (len(t));
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos; tpoint.y = y;
- bfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(bfont[cur], bfont_rect, tpoint);
- bfontpos+=bfontlen[cur];
- }
- }
-
- public function checkFrame(e:Event):void {
- var p:Number = this.loaderInfo.bytesLoaded / this.loaderInfo.bytesTotal;
-
- //if (stage.root.loaderInfo.url.search(/.swf$/) >= 0) p = 0; //Not for the demo!
- transition = -10; fakepercent = 100;
-
- if (transition < 30) transition--;
- if(transition>=30){
- if (int(p * 100) >= fakepercent) fakepercent++;
- if (fakepercent >= 100) {
- fakepercent = 100;
- startgame = true;
- }
-
- offset = (offset + 4 + int(Math.random()*5))%32;
- coltimer--;
- if (coltimer <= 0) {
- curcol = (curcol + int(Math.random() * 5)) % 6;
- coltimer = 8;
- }
- switch(curcol) {
- case 0:
- lightcol = 0xBF596F;
- darkcol = 0x883E53;
- break;
- case 1:
- lightcol = 0x6CBC5C;
- darkcol = 0x508640;
- break;
- case 2:
- lightcol = 0x5D57AA;
- darkcol = 0x2F2F6C;
- break;
- case 3:
- lightcol = 0xB7BA5E;
- darkcol = 0x848342;
- break;
- case 4:
- lightcol = 0x5790AA;
- darkcol = 0x2F5B6C;
- break;
- case 5:
- lightcol = 0x9061B1;
- darkcol = 0x583D71;
- break;
- }
-
- for (var i:int = 0; i < 18; i++) {
- temprect.y = (i * 16) -offset;
- if (i % 2 == 0) {
- backbuffer.fillRect(temprect, lightcol);
- }else{
- backbuffer.fillRect(temprect, darkcol);
- }
- }
-
- backbuffer.fillRect(frontrect, 0x3E31A2);
-
-
- tempstring = "LOADING... " + String(int(fakepercent))+"%";
- print(282, 204, tempstring, 124, 112, 218, true);
-
- //Render
- screenbuffer.lock();
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tl, null, null, false);
- screenbuffer.unlock();
-
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
- if (currentFrame >= totalFrames){
- if (startgame) {
- transition = 29;
- }
- }
- }else if (transition <= -10) {
- if (currentFrame >= totalFrames){
- startup();
- }
- }else if (transition < 5) {
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- //Render
- screenbuffer.lock();
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tl, null, null, false);
- screenbuffer.unlock();
-
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
- }else if (transition < 20) {
- temprect.y = 0;
- temprect.height = 240;
- backbuffer.fillRect(temprect, 0x000000);
- backbuffer.fillRect(frontrect, 0x3E31A2);
-
- tempstring = "LOADING... 100%";
- print(282, 204, tempstring, 124, 112, 218, true);
- //Render
- screenbuffer.lock();
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tl, null, null, false);
- screenbuffer.unlock();
-
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
- }
- }
-
- private function startup():void {
- // hide loader
- //stop();
- removeChild(screen);
- removeEventListener(Event.ENTER_FRAME, checkFrame);
- //loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
- var mainClass:Class = getDefinitionByName("Main") as Class;
- addChild(new mainClass() as DisplayObject);
- //stage.removeChild(this);
- }
-
- public function checksite():Boolean {
- //Returns true if on a site that doesn't use mochiads
- var currUrl:String = stage.loaderInfo.url.toLowerCase();
- //chat.kongregate.com
- if ((currUrl.indexOf("distractionware.com") <= 0) &&
- (currUrl.indexOf("flashgamelicense.com") <= 0) &&
- (currUrl.indexOf("kongregate.com") <= 0) &&
- (currUrl.indexOf("chat.kongregate.com") <= 0)){
- //return true;
- return false;
- }else{
- return true;
- }
- }
-
- public function len(t:String):int {
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- bfontpos+=bfontlen[cur];
- }
- return bfontpos;
- }
-
- public function RGB(red:Number,green:Number,blue:Number):Number{
- return (blue | (green << 8) | (red << 16))
- }
-
- public function makebfont():void {
- for (var j:Number = 0; j < 16; j++) {
- for (var i:Number = 0; i < 16; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var t2emprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, t2emprect, tl);
- bfont.push(t);
- }
- }
-
- //Ok, now we work out the lengths (this data string cortesy of a program I wrote!)
- for (i = 0; i < 256; i++) bfontlen.push(6);
- var maprow:Array;
- var tstring:String="4,3,5,7,6,7,6,3,4,4,7,7,3,5,2,5,6,5,6,6,6,6,6,6,6,6,2,3,5,5,5,6,7,6,6,6,6,5,5,6,6,3,6,6,5,7,7,6,6,6,6,6,5,6,7,7,7,7,5,4,5,4,5,6,4,6,6,6,6,5,5,6,6,3,6,6,5,7,7,6,6,6,6,6,5,6,7,7,7,7,5,5,3,5,6,4";
-
- maprow = new Array();
- maprow = tstring.split(",");
- for(var k:int = 0; k < 96; k++) {
- bfontlen[k + 32] = 8;// int(maprow[k]);
- }
- }
-
- public var darkcol:int, lightcol:int, curcol:int, coltimer:int;
- public var offset:int;
-
- public var buffer:BitmapData;
- public var backbuffer:BitmapData;
- public var screenbuffer:BitmapData;
- public var screen:Bitmap;
-
- public var frontrect:Rectangle;
- public var temprect:Rectangle;
-
- public var showctp:Boolean;
- public var startgame:Boolean;
- public var adson:Boolean;
-
- [Embed(source = '../data/graphics/font.png')] private var im_bfont:Class;
- public var bfontlen:Array = new Array();
- public var bfont:Array = new Array();
- public var bfont_rect:Rectangle;
- public var tl:Point, tpoint:Point;
- public var bfontpos:int;
- public var cur:int;
- public var ct:ColorTransform;
-
- public var tempstring:String;
- public var fakepercent:int;
-
- public var transition:int;
-
- public var statcookie:SharedObject;
- }
-}
\ No newline at end of file
diff --git a/mobile_version/src/blockclass.as b/mobile_version/src/blockclass.as
index 23801faf..864ca8d9 100644
--- a/mobile_version/src/blockclass.as
+++ b/mobile_version/src/blockclass.as
@@ -1,10 +1,7 @@
-package {
- import flash.display.*;
+package {
import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
- public class blockclass extends Sprite {
+ public class blockclass {
public function blockclass():void {
rect = new Rectangle();
clear();
diff --git a/mobile_version/src/com/adobe/utils/AGALMiniAssembler.as b/mobile_version/src/com/adobe/utils/AGALMiniAssembler.as
new file mode 100644
index 00000000..ca511f44
--- /dev/null
+++ b/mobile_version/src/com/adobe/utils/AGALMiniAssembler.as
@@ -0,0 +1,805 @@
+/*
+Copyright (c) 2015, Adobe Systems Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems Incorporated nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package com.adobe.utils
+{
+ // ===========================================================================
+ // Imports
+ // ---------------------------------------------------------------------------
+ import flash.display3D.*;
+ import flash.utils.*;
+
+ // ===========================================================================
+ // Class
+ // ---------------------------------------------------------------------------
+ public class AGALMiniAssembler
+ { // ======================================================================
+ // Constants
+ // ----------------------------------------------------------------------
+ protected static const REGEXP_OUTER_SPACES:RegExp = /^\s+|\s+$/g;
+
+ // ======================================================================
+ // Properties
+ // ----------------------------------------------------------------------
+ // AGAL bytes and error buffer
+ private var _agalcode:ByteArray = null;
+ private var _error:String = "";
+
+ private var debugEnabled:Boolean = false;
+
+ private static var initialized:Boolean = false;
+ public var verbose:Boolean = false;
+
+ // ======================================================================
+ // Getters
+ // ----------------------------------------------------------------------
+ public function get error():String { return _error; }
+ public function get agalcode():ByteArray { return _agalcode; }
+
+ // ======================================================================
+ // Constructor
+ // ----------------------------------------------------------------------
+ public function AGALMiniAssembler( debugging:Boolean = false ):void
+ {
+ debugEnabled = debugging;
+ if ( !initialized )
+ init();
+ }
+ // ======================================================================
+ // Methods
+ // ----------------------------------------------------------------------
+
+ public function assemble2( ctx3d : Context3D, version:uint, vertexsrc:String, fragmentsrc:String ) : Program3D
+ {
+ var agalvertex : ByteArray = assemble ( VERTEX, vertexsrc, version );
+ var agalfragment : ByteArray = assemble ( FRAGMENT, fragmentsrc, version );
+ var prog : Program3D = ctx3d.createProgram();
+ prog.upload(agalvertex,agalfragment);
+ return prog;
+ }
+
+ public function assemble( mode:String, source:String, version:uint=1, ignorelimits:Boolean=false ):ByteArray
+ {
+ var start:uint = getTimer();
+
+ _agalcode = new ByteArray();
+ _error = "";
+
+ var isFrag:Boolean = false;
+
+ if ( mode == FRAGMENT )
+ isFrag = true;
+ else if ( mode != VERTEX )
+ _error = 'ERROR: mode needs to be "' + FRAGMENT + '" or "' + VERTEX + '" but is "' + mode + '".';
+
+ agalcode.endian = Endian.LITTLE_ENDIAN;
+ agalcode.writeByte( 0xa0 ); // tag version
+ agalcode.writeUnsignedInt( version ); // AGAL version, big endian, bit pattern will be 0x01000000
+ agalcode.writeByte( 0xa1 ); // tag program id
+ agalcode.writeByte( isFrag ? 1 : 0 ); // vertex or fragment
+
+ initregmap(version, ignorelimits);
+
+ var lines:Array = source.replace( /[\f\n\r\v]+/g, "\n" ).split( "\n" );
+ var nest:int = 0;
+ var nops:int = 0;
+ var i:int;
+ var lng:int = lines.length;
+
+ for ( i = 0; i < lng && _error == ""; i++ )
+ {
+ var line:String = new String( lines[i] );
+ line = line.replace( REGEXP_OUTER_SPACES, "" );
+
+ // remove comments
+ var startcomment:int = line.search( "//" );
+ if ( startcomment != -1 )
+ line = line.slice( 0, startcomment );
+
+ // grab options
+ var optsi:int = line.search( /<.*>/g );
+ var opts:Array;
+ if ( optsi != -1 )
+ {
+ opts = line.slice( optsi ).match( /([\w\.\-\+]+)/gi );
+ line = line.slice( 0, optsi );
+ }
+
+ // find opcode
+ var opCode:Array = line.match( /^\w{3}/ig );
+ if ( !opCode )
+ {
+ if ( line.length >= 3 )
+ trace( "warning: bad line "+i+": "+lines[i] );
+ continue;
+ }
+ var opFound:OpCode = OPMAP[ opCode[0] ];
+
+ // if debug is enabled, output the opcodes
+ if ( debugEnabled )
+ trace( opFound );
+
+ if ( opFound == null )
+ {
+ if ( line.length >= 3 )
+ trace( "warning: bad line "+i+": "+lines[i] );
+ continue;
+ }
+
+ line = line.slice( line.search( opFound.name ) + opFound.name.length );
+
+ if ( ( opFound.flags & OP_VERSION2 ) && version<2 )
+ {
+ _error = "error: opcode requires version 2.";
+ break;
+ }
+
+ if ( ( opFound.flags & OP_VERT_ONLY ) && isFrag )
+ {
+ _error = "error: opcode is only allowed in vertex programs.";
+ break;
+ }
+
+ if ( ( opFound.flags & OP_FRAG_ONLY ) && !isFrag )
+ {
+ _error = "error: opcode is only allowed in fragment programs.";
+ break;
+ }
+ if ( verbose )
+ trace( "emit opcode=" + opFound );
+
+ agalcode.writeUnsignedInt( opFound.emitCode );
+ nops++;
+
+ if ( nops > MAX_OPCODES )
+ {
+ _error = "error: too many opcodes. maximum is "+MAX_OPCODES+".";
+ break;
+ }
+
+ // get operands, use regexp
+ var regs:Array;
+
+ // will match both syntax
+ regs = line.match( /vc\[([vof][acostdip]?)(\d*)?(\.[xyzw](\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vof][acostdip]?)(\d*)?(\.[xyzw]{1,4})?/gi );
+
+ if ( !regs || regs.length != opFound.numRegister )
+ {
+ _error = "error: wrong number of operands. found "+regs.length+" but expected "+opFound.numRegister+".";
+ break;
+ }
+
+ var badreg:Boolean = false;
+ var pad:uint = 64 + 64 + 32;
+ var regLength:uint = regs.length;
+
+ for ( var j:int = 0; j < regLength; j++ )
+ {
+ var isRelative:Boolean = false;
+ var relreg:Array = regs[ j ].match( /\[.*\]/ig );
+ if ( relreg && relreg.length > 0 )
+ {
+ regs[ j ] = regs[ j ].replace( relreg[ 0 ], "0" );
+
+ if ( verbose )
+ trace( "IS REL" );
+ isRelative = true;
+ }
+
+ var res:Array = regs[j].match( /^\b[A-Za-z]{1,2}/ig );
+ if ( !res )
+ {
+ _error = "error: could not parse operand "+j+" ("+regs[j]+").";
+ badreg = true;
+ break;
+ }
+ var regFound:Register = REGMAP[ res[ 0 ] ];
+
+ // if debug is enabled, output the registers
+ if ( debugEnabled )
+ trace( regFound );
+
+ if ( regFound == null )
+ {
+ _error = "error: could not find register name for operand "+j+" ("+regs[j]+").";
+ badreg = true;
+ break;
+ }
+
+ if ( isFrag )
+ {
+ if ( !( regFound.flags & REG_FRAG ) )
+ {
+ _error = "error: register operand "+j+" ("+regs[j]+") only allowed in vertex programs.";
+ badreg = true;
+ break;
+ }
+ if ( isRelative )
+ {
+ _error = "error: register operand "+j+" ("+regs[j]+") relative adressing not allowed in fragment programs.";
+ badreg = true;
+ break;
+ }
+ }
+ else
+ {
+ if ( !( regFound.flags & REG_VERT ) )
+ {
+ _error = "error: register operand "+j+" ("+regs[j]+") only allowed in fragment programs.";
+ badreg = true;
+ break;
+ }
+ }
+
+ regs[j] = regs[j].slice( regs[j].search( regFound.name ) + regFound.name.length );
+ //trace( "REGNUM: " +regs[j] );
+ var idxmatch:Array = isRelative ? relreg[0].match( /\d+/ ) : regs[j].match( /\d+/ );
+ var regidx:uint = 0;
+
+ if ( idxmatch )
+ regidx = uint( idxmatch[0] );
+
+ if ( regFound.range < regidx )
+ {
+ _error = "error: register operand "+j+" ("+regs[j]+") index exceeds limit of "+(regFound.range+1)+".";
+ badreg = true;
+ break;
+ }
+
+ var regmask:uint = 0;
+ var maskmatch:Array = regs[j].match( /(\.[xyzw]{1,4})/ );
+ var isDest:Boolean = ( j == 0 && !( opFound.flags & OP_NO_DEST ) );
+ var isSampler:Boolean = ( j == 2 && ( opFound.flags & OP_SPECIAL_TEX ) );
+ var reltype:uint = 0;
+ var relsel:uint = 0;
+ var reloffset:int = 0;
+
+ if ( isDest && isRelative )
+ {
+ _error = "error: relative can not be destination";
+ badreg = true;
+ break;
+ }
+
+ if ( maskmatch )
+ {
+ regmask = 0;
+ var cv:uint;
+ var maskLength:uint = maskmatch[0].length;
+ for ( var k:int = 1; k < maskLength; k++ )
+ {
+ cv = maskmatch[0].charCodeAt(k) - "x".charCodeAt(0);
+ if ( cv > 2 )
+ cv = 3;
+ if ( isDest )
+ regmask |= 1 << cv;
+ else
+ regmask |= cv << ( ( k - 1 ) << 1 );
+ }
+ if ( !isDest )
+ for ( ; k <= 4; k++ )
+ regmask |= cv << ( ( k - 1 ) << 1 ); // repeat last
+ }
+ else
+ {
+ regmask = isDest ? 0xf : 0xe4; // id swizzle or mask
+ }
+
+ if ( isRelative )
+ {
+ var relname:Array = relreg[0].match( /[A-Za-z]{1,2}/ig );
+ var regFoundRel:Register = REGMAP[ relname[0]];
+ if ( regFoundRel == null )
+ {
+ _error = "error: bad index register";
+ badreg = true;
+ break;
+ }
+ reltype = regFoundRel.emitCode;
+ var selmatch:Array = relreg[0].match( /(\.[xyzw]{1,1})/ );
+ if ( selmatch.length==0 )
+ {
+ _error = "error: bad index register select";
+ badreg = true;
+ break;
+ }
+ relsel = selmatch[0].charCodeAt(1) - "x".charCodeAt(0);
+ if ( relsel > 2 )
+ relsel = 3;
+ var relofs:Array = relreg[0].match( /\+\d{1,3}/ig );
+ if ( relofs.length > 0 )
+ reloffset = relofs[0];
+ if ( reloffset < 0 || reloffset > 255 )
+ {
+ _error = "error: index offset "+reloffset+" out of bounds. [0..255]";
+ badreg = true;
+ break;
+ }
+ if ( verbose )
+ trace( "RELATIVE: type="+reltype+"=="+relname[0]+" sel="+relsel+"=="+selmatch[0]+" idx="+regidx+" offset="+reloffset );
+ }
+
+ if ( verbose )
+ trace( " emit argcode="+regFound+"["+regidx+"]["+regmask+"]" );
+ if ( isDest )
+ {
+ agalcode.writeShort( regidx );
+ agalcode.writeByte( regmask );
+ agalcode.writeByte( regFound.emitCode );
+ pad -= 32;
+ } else
+ {
+ if ( isSampler )
+ {
+ if ( verbose )
+ trace( " emit sampler" );
+ var samplerbits:uint = 5; // type 5
+ var optsLength:uint = opts == null ? 0 : opts.length;
+ var bias:Number = 0;
+ for ( k = 0; k 50){
bvx = 9 - (Math.random() * 19); if (bvx > -6 && bvx < 6) bvx = 6;
- bvx = bvx * 1.5;
+ bvx = bvx * 1.5;
bb = new Rectangle(Math.random() * 320, Math.random() * 240, 32, 12);
}else {
bvy = 9 - (Math.random() * 19); if (bvy > -6 && bvy < 6) bvy = 6;
- bvy = bvy * 1.5;
+ bvy = bvy * 1.5;
bb = new Rectangle(Math.random() * 320, Math.random() * 240, 12, 32);
}
var bint:Number = 0.5 + ((Math.random() * 100) / 200);
@@ -77,7 +144,7 @@
crewframe = 0; crewframedelay = 4;
menuoffset = 0; resumegamemode = false;
- //Textboxes!
+ //Textboxes!
for (i = 0; i < 30; i++) {
var t:textboxclass = new textboxclass;
textbox.push(t);
@@ -91,67 +158,27 @@
fadeamount = 0;
fademode = 0;
- bigbuffer = new BitmapData(320, 32, true, 0x000000);
- bigbufferscreen = new Bitmap(bigbuffer);
- bigbufferscreen.width = 640;
- bigbufferscreen.height = 20;
- towerbuffer = new BitmapData(320, 240, true, 0x000000);
- frontbuffer = new BitmapData(320, 240, true, 0x000000);
+ //var devicexres:int = int(Capabilities.screenResolutionX);
+ //var deviceyres:int = int(Capabilities.screenResolutionY);
+ //updatescreen(starstage.stageWidth, starstage.stageHeight);
- menubuffer = new BitmapData(320, 240, false, 0x000000); //yeah yeah I know this is lazy
-
- backbuffer=new BitmapData(320, 240,false,0x000000);
- screenbuffer = new BitmapData(320,240,false,0x000000);
-
- temptile = new BitmapData(8, 8, false, 0x000000);
- tempsprite = new BitmapData(32, 32, false, 0x000000);
- screen = new Bitmap(screenbuffer);
-
- //screen.width = 640;//320;//;640;
- //screen.height = 480;// 240;//480;
- screen.smoothing = true;
-
- addChild(screen);
-
- buttonscreen.push(new Bitmap(buttonimg[0]));
- buttonscreen.push(new Bitmap(buttonimg[1]));
- buttonscreen.push(new Bitmap(buttonimg[2]));
- buttonscreen.push(new Bitmap(buttonimg[3]));
-
- /*
- if (device.deviceresolution == device.IPAD) {
- buttonsize = 90;
- buttonyspacing = buttonsize / 3;
- buttonxspacing = 40;
- buttonscreen[0].width = 92*3; buttonscreen[0].height = buttonsize;
- buttonscreen[1].width = 92*3; buttonscreen[1].height = buttonsize;
- buttonscreen[2].width = 40*3; buttonscreen[2].height = 40*3;
- buttonscreen[3].width = 40 * 3; buttonscreen[3].height = 40 * 3;
- buttonydiff = buttonscreen[2].height / 2;
- }else if (device.deviceresolution == device.ANDROID) {
- */
-
- /*
- }else {
- buttonsize = 30;
- buttonyspacing = buttonsize / 3;
- buttonxspacing = 20;
- buttonscreen[0].width = 92; buttonscreen[0].height = buttonsize;
- buttonscreen[1].width = 92; buttonscreen[1].height = buttonsize;
- buttonscreen[2].width = 40; buttonscreen[2].height = 40;
- buttonscreen[3].width = 40; buttonscreen[3].height = 40;
- buttonydiff = buttonscreen[2].height / 2;
- }
- */
-
- /*buttonscreen.push(new Bitmap(buttonimg[1]));
- buttonscreen[1].width = buttonsize; buttonscreen[1].height = buttonsize;
- buttonscreen.push(new Bitmap(buttonimg[2]));
- buttonscreen[2].width = buttonsize; buttonscreen[2].height = buttonsize;
- buttonscreen.push(new Bitmap(buttonimg[3]));
- buttonscreen[3].width = buttonsize; buttonscreen[3].height = buttonsize;
- */
+ //Starling.current.showStats = true;
+ }
+
+ public function initbuttonstuff():void {
+ button_image_width.push(0); button_image_height.push(0);
+ button_image_width.push(0); button_image_height.push(0);
+ button_image_width.push(0); button_image_height.push(0);
+ button_image_width.push(0); button_image_height.push(0);
+ button_image.push(new Image(button_texture[0]));
+ button_image.push(new Image(button_texture[1]));
+ button_image.push(new Image(button_texture[2]));
+ button_image.push(new Image(button_texture[3]));
+ button_image[0].touchable = false; button_image[0].textureSmoothing = TextureSmoothing.NONE;
+ button_image[1].touchable = false; button_image[1].textureSmoothing = TextureSmoothing.NONE;
+ button_image[2].touchable = false; button_image[2].textureSmoothing = TextureSmoothing.NONE;
+ button_image[3].touchable = false; button_image[3].textureSmoothing = TextureSmoothing.NONE;
for (i = 0; i < 10; i++) {
buttonlerp.push(int(0));
@@ -172,72 +199,81 @@
initbuttonpositions();
- /*
- buttonscreen[0].x = buttonxspacing;
- buttonscreen[0].y = device.yres - buttonsize-buttonyspacing-buttonydiff;
- buttonpos.push(new Point(buttonscreen[0].x, buttonscreen[0].y));
-
- buttonscreen[1].x = buttonxspacing + buttonsize + buttonxspacing;
- buttonscreen[1].y = device.yres - buttonsize-buttonyspacing;
- buttonpos.push(new Point(buttonscreen[1].x, buttonscreen[1].y));
-
- buttonscreen[2].x = device.xres - buttonxspacing - buttonsize;
- buttonscreen[2].y = buttonsize / 4;
- buttonpos.push(new Point(buttonscreen[2].x, buttonscreen[2].y));
-
- buttonscreen[3].x = device.xres - buttonxspacing - buttonsize - buttonxspacing - buttonsize;
- buttonscreen[3].y = device.yres - buttonsize-buttonyspacing;
- buttonpos.push(new Point(buttonscreen[3].x, buttonscreen[3].y));
- */
drawonscreenbutton(0, -1);
drawonscreenbutton(1, -1);
drawonscreenbutton(2, -1);
drawonscreenbutton(3, -1);
- addChild(buttonscreen[0]);
- addChild(buttonscreen[1]);
- addChild(buttonscreen[2]);
- addChild(buttonscreen[3]);
- /*
- drawonscreenbutton(0, 0);
- drawonscreenbutton(1, 0);
- drawonscreenbutton(2, 0);
- drawonscreenbutton(3, 0);
- showarrows();
- */
- }
+ starstage.addChild(button_image[0]);
+ starstage.addChild(button_image[1]);
+ starstage.addChild(button_image[2]);
+ starstage.addChild(button_image[3]);
+
+ buttonsready = true;
+ }
+
+ public function updatescreen(w:int, h:int):void {
+ starstage.stageWidth = w;
+ starstage.stageHeight = h;
+
+ Starling.current.viewPort = new Rectangle(0, 0, w, h);
+
+ // set rectangle dimensions for viewPort:
+ var stretchscalex:Number = w / screenwidth;
+ var stretchscaley:Number = h / screenheight;
+ screensizemultiplier = Math.min(stretchscalex, stretchscaley);
+
+ //Never mess with starling's viewport for VVVVVV - instead, mess with the
+ //screen image
+ screen.width = screenwidth * screensizemultiplier;
+ screen.height = screenheight * screensizemultiplier;
+
+ screen.x = (w / 2) - (screenwidth * screensizemultiplier / 2);
+ }
public function initbuttonpositions():void {
- devicex = device.xres;
+ devicex = device.xres;
devicey = device.yres;
- buttonsize = device.yres / (32 / 3);
+ buttonsize = devicey / (32 / 3);
buttonyspacing = buttonsize / 3;
- buttonxspacing = (buttonsize * 3) / 3;
- buttonscreen[0].width = (buttonsize * 46) / 15; buttonscreen[0].height = buttonsize;
- buttonscreen[1].width = (buttonsize * 46) / 15; buttonscreen[1].height = buttonsize;
- buttonscreen[2].width = (buttonsize * 5) / 3; buttonscreen[2].height = (buttonsize * 5) / 3;
- buttonscreen[3].width = (buttonsize * 5) / 3; buttonscreen[3].height = (buttonsize * 5) / 3;
- buttonydiff = buttonscreen[2].height / 2;
+ buttonxspacing = (buttonsize * 3) / 3;
- buttonscreen[0].x = device.xres + 1;
- buttonscreen[0].y = 0;
- buttonpos[0].setTo(buttonscreen[0].x, buttonscreen[0].y);
+ button_image[0].width = (buttonsize * 46) / 15; button_image[0].height = buttonsize;
+ button_image[1].width = (buttonsize * 46) / 15; button_image[1].height = buttonsize;
+ button_image[2].width = (buttonsize * 5) / 3; button_image[2].height = (buttonsize * 5) / 3;
+ button_image[3].width = (buttonsize * 5) / 3; button_image[3].height = (buttonsize * 5) / 3;
- buttonscreen[1].x = 0;
- buttonscreen[1].y = 0;
- buttonpos[1].setTo(buttonscreen[1].x, buttonscreen[1].y);
+ button_image_width[0] = int(button_image[0].width);
+ button_image_width[1] = int(button_image[1].width);
+ button_image_width[2] = int(button_image[2].width);
+ button_image_width[3] = int(button_image[3].width);
+ button_image_height[0] = int(button_image[0].height);
+ button_image_height[1] = int(button_image[1].height);
+ button_image_height[2] = int(button_image[2].height);
+ button_image_height[3] = int(button_image[3].height);
- buttonscreen[2].x = (buttonxspacing / 2);
- buttonscreen[2].y = device.yres - buttonsize-buttonyspacing - buttonydiff;
- buttonpos[2].setTo(buttonscreen[2].x, buttonscreen[2].y);
- buttonscreen[3].x = (buttonxspacing/2) + buttonsize + buttonxspacing;
- buttonscreen[3].y = device.yres - buttonsize-buttonyspacing;
- buttonpos[3].setTo(buttonscreen[3].x, buttonscreen[3].y);
+ buttonydiff = button_image_height[2] / 2;
+
+ button_image[0].x = devicex + 1;
+ button_image[0].y = 0;
+ buttonpos[0].setTo(button_image[0].x, button_image[0].y);
+
+ button_image[1].x = 0;
+ button_image[1].y = 0;
+ buttonpos[1].setTo(button_image[1].x, button_image[1].y);
+
+ button_image[2].x = (buttonxspacing / 2);
+ button_image[2].y = devicey - buttonsize-buttonyspacing - buttonydiff;
+ buttonpos[2].setTo(button_image[2].x, button_image[2].y);
+
+ button_image[3].x = (buttonxspacing/2) + buttonsize + buttonxspacing ;
+ button_image[3].y = devicey - buttonsize-buttonyspacing;
+ buttonpos[3].setTo(button_image[3].x, button_image[3].y);
}
public function mobile_changebutton(t:int):void {
- if (newbuttontype[0] != t) {
+ if (newbuttontype[0] != t) {
if (currentbuttontype[0] != t) {
newbuttontype[0] = t;
buttonstate[0] = 1;
@@ -246,7 +282,7 @@
}
public function mobile_changeleftbutton(t:int):void {
- if (newbuttontype[1] != t) {
+ if (newbuttontype[1] != t) {
if (currentbuttontype[1] != t) {
newbuttontype[1] = t;
buttonstate[1] = 1;
@@ -275,7 +311,7 @@
}
public function drawbutton(game:gameclass, help:helpclass):void {
- //Called every frame, this function controls what buttons appear and when,
+ //Called every frame, this function controls what buttons appear and when,
//and lerps them in and out in a nice way.
//buttonstate[0]:
// 0 - Normal, slide in if not in
@@ -319,13 +355,13 @@
changebuttonframe(3, 12);
if (game.press_left) {
- changebuttonpos(2, buttonxspacing/2, devicey - buttonsize-buttonyspacing - buttonydiff+10);
+ changebuttonpos(2, (buttonxspacing/2), devicey - buttonsize-buttonyspacing - buttonydiff+10);
}else{
- changebuttonpos(2, buttonxspacing/2, devicey - buttonsize-buttonyspacing - buttonydiff);
+ changebuttonpos(2, (buttonxspacing/2), devicey - buttonsize-buttonyspacing - buttonydiff);
}
if (game.press_right) {
- changebuttonpos(3, (buttonxspacing/2)+ buttonsize + buttonxspacing, devicey - buttonsize-buttonyspacing - buttonydiff+10);
+ changebuttonpos(3, (buttonxspacing/2) + buttonsize + buttonxspacing, devicey - buttonsize-buttonyspacing - buttonydiff+10);
}else{
changebuttonpos(3, (buttonxspacing/2) + buttonsize + buttonxspacing, devicey - buttonsize-buttonyspacing - buttonydiff);
}
@@ -336,7 +372,7 @@
case BUTTON_BLANK:
//Blank
changebuttonframe(1, -1);
- changebuttonpos(1, 0 - ((buttonscreen[1].width * (buttonlerp[1])) / 100), 0);
+ changebuttonpos(1, 0 - ((button_image_width[1] * (buttonlerp[1])) / 100), 0);
break;
case BUTTON_CONTROLS:
//Controls button
@@ -346,15 +382,15 @@
changebuttonframe(1, 8);
}
if (flipmode) {
- changebuttonpos(1, 0 - ((buttonscreen[1].width * (buttonlerp[1])) / 100), devicey-buttonyspacing-buttonscreen[1].height);
+ changebuttonpos(1, 0 - ((button_image_width[1] * (buttonlerp[1])) / 100), devicey - buttonyspacing - button_image_height[1]);
}else {
- changebuttonpos(1, 0 - ((buttonscreen[1].width * (buttonlerp[1])) / 100), buttonyspacing);
+ changebuttonpos(1, 0 - ((button_image_width[1] * (buttonlerp[1])) / 100), buttonyspacing);
}
break;
case BUTTON_GAMECENTER:
changebuttonframe(1, 10);
- changebuttonpos(1, 0 - ((buttonscreen[1].width * (buttonlerp[1])) / 100), 5);
+ changebuttonpos(1, 0 - ((button_image_width[1] * (buttonlerp[1])) / 100), 5);
break;
}
@@ -362,20 +398,20 @@
case BUTTON_BLANK:
//Blank
changebuttonframe(0, -1);
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100-buttonlerp[0])) / 100), 0);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100-buttonlerp[0])) / 100), 0);
break;
case BUTTON_MENU:
//Menu button
changebuttonframe(0, 0);
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100-buttonlerp[0])) / 100), 0);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100-buttonlerp[0])) / 100), 0);
break;
case BUTTON_BACK:
//Back button
changebuttonframe(0, 1);
if (flipmode) {
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100 - buttonlerp[0])) / 100), devicey - buttonyspacing - buttonscreen[0].height);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100 - buttonlerp[0])) / 100), devicey - buttonyspacing - button_image_height[0]);
}else{
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100 - buttonlerp[0])) / 100), buttonyspacing);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100 - buttonlerp[0])) / 100), buttonyspacing);
}
break;
case BUTTON_USE:
@@ -385,7 +421,7 @@
}else {
changebuttonframe(0, 5);
}
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100-buttonlerp[0])) / 100), buttonyspacing);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100-buttonlerp[0])) / 100), buttonyspacing);
break;
case BUTTON_TALK:
//Talk button
@@ -394,7 +430,7 @@
}else {
changebuttonframe(0, 3);
}
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100-buttonlerp[0])) / 100), buttonyspacing);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100-buttonlerp[0])) / 100), buttonyspacing);
break;
case BUTTON_TELEPORT:
//Teleport button
@@ -403,48 +439,34 @@
}else {
changebuttonframe(0, 7);
}
- changebuttonpos(0, devicex - ((buttonscreen[0].width * (100-buttonlerp[0])) / 100), buttonyspacing);
+ changebuttonpos(0, devicex - ((button_image_width[0] * (100-buttonlerp[0])) / 100), buttonyspacing);
break;
}
-
- /*
- if (game.press_left) { drawonscreenbutton(0, 1);
- }else{ drawonscreenbutton(0, 0);}
-
- if (game.press_right) { drawonscreenbutton(1, 1);
- }else { drawonscreenbutton(1, 0); }
-
- if (game.press_map) { drawonscreenbutton(2, 1);
- }else { drawonscreenbutton(2, 0); }
- */
- //Draw circle pad!
- //if (key.controlstick != -1) {
- /*
- backbuffer.copyPixels(dwgfx.buttonimg[13], dwgfx.buttonimg[13].rect, new Point(key.controlstick_x - 18+18, key.controlstick_y - 18+18));
- for (i = 0; i < key.touchPoints; i++) {
- if (key.touchid[i] == key.controlstick) {
- dwgfx.backbuffer.copyPixels(dwgfx.buttonimg[14], dwgfx.buttonimg[14].rect, new Point(key.touchx[i] - 18, key.touchy[i] - 18));
- }
- }
- */
- //}
}
- public function addbutton():void {
- var t:BitmapData = new BitmapData(buffer.width, buffer.height, true, 0x00000000);
- t.copyPixels(buffer, new Rectangle(0,0,buffer.width, buffer.height), new Point(0,0));
- buttonimg.push(t);
+ public function addbutton(imgname:String):void {
+ var sourcetexture:Texture = starlingassets.getTexture(imgname);
+ var tmpimage:Image = new Image(sourcetexture);
+
+ var newtexture:RenderTexture = new RenderTexture(int(tmpimage.texture.width), int(tmpimage.texture.height));
+ newtexture.draw(tmpimage);
+
+ sourcetexture.dispose();
+ tmpimage.dispose();
+
+ button_texture.push(newtexture);
}
public function drawonscreenbutton(t:int, t2:int):void {
//Draw button t with frame t2
if (t2 == -1) {
- buttonimg[t].fillRect(buttonimg[t].rect, 0x00000000);
+ button_texture[t].clear();
}
if (buttonframe[t] != t2) {
buttonframe[t] = t2;
- buttonimg[t].fillRect(buttonimg[t].rect, 0x00000000);
- buttonimg[t].copyPixels(buttonimg[4 + t2], buttonimg[t].rect, tl);
+ button_texture[t].clear();
+ var tempimg:Image = new Image(button_texture[4 + t2]);
+ button_texture[t].draw(tempimg);
}
}
@@ -453,167 +475,169 @@
if (buttonframe[t] != t2) {
buttonframe[t] = t2;
if (t2 == -1) {
- buttonimg[t].fillRect(buttonimg[t].rect, 0x00000000);
+ button_texture[t].clear();
}else{
- buttonimg[t].fillRect(buttonimg[t].rect, 0x00000000);
- buttonimg[t].copyPixels(buttonimg[4 + t2], buttonimg[t].rect, tl);
+ button_texture[t].clear();
+ var tempimg:Image = new Image(button_texture[4 + t2]);
+ button_texture[t].draw(tempimg);
}
}
}
public function changebuttonpos(t:int, xp:int, yp:int):void {
- buttonscreen[t].x = xp;
- buttonscreen[t].y = yp;
+ button_image[t].x = xp;
+ button_image[t].y = yp;
}
public function changebuttonxpos(t:int, xp:int):void {
- buttonscreen[t].x = xp;
+ button_image[t].x = xp;
}
public function showarrows():void {
if (buttonactive[0] == false) {
buttonhighlight[0] = 120;
buttonactive[0] = true;
- addChild(buttonscreen[0]);
- addChild(buttonscreen[1]);
- addChild(buttonscreen[2]);
+ starstage.addChild(button_image[0]);
+ starstage.addChild(button_image[1]);
+ starstage.addChild(button_image[2]);
}
}
public function hidearrows():void {
if (buttonactive[0] == true) {
buttonactive[0] = false;
- removeChild(buttonscreen[0]);
- removeChild(buttonscreen[1]);
- removeChild(buttonscreen[2]);
+ starstage.removeChild(button_image[0]);
+ starstage.removeChild(button_image[1]);
+ starstage.removeChild(button_image[2]);
}
}
-
public function drawspritesetcol(x:int, y:int, t:int, c:int, help:helpclass):void {
- tpoint.x = x; tpoint.y = y;
- setcol(c, help);
- sprites[t].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[t], sprites_rect, tpoint);
- }
-
-
- public function makebfont():void {
- for (var j:Number = 0; j < 16; j++) {
- for (var i:Number = 0; i < 16; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var t2:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, temprect, tl);
- t2.draw(t, flipfontmatrix);
- bfont.push(t);
- flipbfont.push(t2);
- }
- }
-
- //Ok, now we work out the lengths (this data string cortesy of a program I wrote!)
- for (i = 0; i < 256; i++) bfontlen.push(6);
- var maprow:Array;
- var tstring:String="4,3,5,7,6,7,6,3,4,4,7,7,3,5,2,5,6,5,6,6,6,6,6,6,6,6,2,3,5,5,5,6,7,6,6,6,6,5,5,6,6,3,6,6,5,7,7,6,6,6,6,6,5,6,7,7,7,7,5,4,5,4,5,6,4,6,6,6,6,5,5,6,6,3,6,6,5,7,7,6,6,6,6,6,5,6,7,7,7,7,5,5,3,5,6,4";
-
- maprow = new Array();
- maprow = tstring.split(",");
- for(var k:int = 0; k < 96; k++) {
- bfontlen[k + 32] = 8;// int(maprow[k]);
- }
- }
-
- public function makebfontmask():void {
- for (var j:Number = 0; j < 16; j++) {
- for (var i:Number = 0; i < 16; i++) {
- var t:BitmapData = new BitmapData(9, 9, true, 0x000000);
- var t2:BitmapData = new BitmapData(9, 9, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 9, j * 9, 9, 9);
- t.copyPixels(buffer, temprect, tl);
- t2.draw(t, flipfontmatrix2);
- bfontmask.push(t);
- flipbfontmask.push(t2);
- }
- }
+ setcol(c, help);
+ sprites[t].color = ct.color;
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(sprites[t], tposition);
}
public function makeentcolourarray():void {
- for (var j:Number = 0; j < 60; j++) {
- for (var i:Number = 0; i < 12; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, temprect, tl);
+ var sourcetexture:Texture = starlingassets.getTexture("entcolours");
+ for (var j:int = 0; j < 60; j++) {
+ for (var i:int = 0; i < 12; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 8, j * 8, 8, 8));
+ var t:Image = new Image(tiletex);
+ t.textureSmoothing = TextureSmoothing.NONE;
+ t.touchable = false;
entcolours.push(t);
}
}
}
public function maketilearray():void {
- for (var j:Number = 0; j < 30; j++) {
- for (var i:Number = 0; i < 40; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, temprect, tl);
- tiles.push(t);
+ var sourcetexture:Texture = starlingassets.getTexture("tiles");
+ for (var j:int = 0; j < 30; j++) {
+ for (var i:int = 0; i < 40; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 8, j * 8, 8, 8));
+ var tile:Image = new Image(tiletex);
+ tile.textureSmoothing = TextureSmoothing.NONE;
+ tile.touchable = false;
+ tiles.push(tile);
}
}
}
public function maketile2array():void {
- for (var j:Number = 0; j < 30; j++) {
- for (var i:Number = 0; i < 40; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, temprect, tl);
- tiles2.push(t);
+ var sourcetexture:Texture = starlingassets.getTexture("tiles2");
+ for (var j:int = 0; j < 30; j++) {
+ for (var i:int = 0; i < 40; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 8, j * 8, 8, 8));
+ var tile:Image = new Image(tiletex);
+ tile.textureSmoothing = TextureSmoothing.NONE;
+ tile.touchable = false;
+ tiles2.push(tile);
}
}
}
public function maketile3array():void {
- for (var j:Number = 0; j < 30; j++) {
- for (var i:Number = 0; i < 30; i++) {
- var t:BitmapData = new BitmapData(8, 8, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 8, j * 8, 8, 8);
- t.copyPixels(buffer, temprect, tl);
- tiles3.push(t);
+ var sourcetexture:Texture = starlingassets.getTexture("tiles3");
+ for (var j:int = 0; j < 30; j++) {
+ for (var i:int = 0; i < 30; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 8, j * 8, 8, 8));
+ var tile:Image = new Image(tiletex);
+ tile.textureSmoothing = TextureSmoothing.NONE;
+ tile.touchable = false;
+ tiles3.push(tile);
}
}
}
public function makespritearray():void {
- for (var j:Number = 0; j < 16; j++) {
- for (var i:Number = 0; i < 12; i++) {
- var t:BitmapData = new BitmapData(32, 32, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 32, j * 32, 32, 32);
- t.copyPixels(buffer, temprect, tl);
+ var sourcetexture:Texture = starlingassets.getTexture("sprites");
+ for (var j:int = 0; j < 16; j++) {
+ for (var i:int = 0; i < 12; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 32, j * 32, 32, 32));
+ var t:Image = new Image(tiletex);
+ t.textureSmoothing = TextureSmoothing.NONE;
+ t.touchable = false;
sprites.push(t);
}
}
+
+ //Sprites also need to load flash bitmapdatas, which are used for pixel perfect hittests
+ var b:Bitmap = new img_bitmapsprites();
+ var buffer:BitmapData = b.bitmapData;
+
+ for (j = 0; j < 16; j++) {
+ for (i = 0; i < 12; i++) {
+ var tb:BitmapData = new BitmapData(32, 32, true, 0x000000);
+ var temprect:Rectangle = new Rectangle(i * 32, j * 32, 32, 32);
+ tb.copyPixels(buffer, temprect, tl);
+ sprites_bitmap.push(tb);
+ }
+ }
}
public function makeflipspritearray():void {
- for (var j:Number = 0; j < 16; j++) {
- for (var i:Number = 0; i < 12; i++) {
- var t:BitmapData = new BitmapData(32, 32, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 32, j * 32, 32, 32);
- t.copyPixels(buffer, temprect, tl);
+ var sourcetexture:Texture = starlingassets.getTexture("flipsprites");
+ for (var j:int = 0; j < 16; j++) {
+ for (var i:int = 0; i < 12; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 32, j * 32, 32, 32));
+ var t:Image = new Image(tiletex);
+ t.textureSmoothing = TextureSmoothing.NONE;
+ t.touchable = false;
flipsprites.push(t);
}
}
+
+
+ //Sprites also need to load flash bitmapdatas, which are used for pixel perfect hittests
+ var b:Bitmap = new img_bitmapflipsprites();
+ var buffer:BitmapData = b.bitmapData;
+
+ for (j = 0; j < 16; j++) {
+ for (i = 0; i < 12; i++) {
+ var tb:BitmapData = new BitmapData(32, 32, true, 0x000000);
+ var temprect:Rectangle = new Rectangle(i * 32, j * 32, 32, 32);
+ tb.copyPixels(buffer, temprect, tl);
+ flipsprites_bitmap.push(tb);
+ }
+ }
}
public function maketelearray():void {
- for (var i:Number = 0; i < 10; i++) {
- var t:BitmapData = new BitmapData(96, 96, true, 0x000000);
- var temprect:Rectangle = new Rectangle(i * 96, 0, 96, 96);
- t.copyPixels(buffer, temprect, tl);
+ var sourcetexture:Texture = starlingassets.getTexture("teleporter");
+ for (var i:int = 0; i < 10; i++) {
+ var tiletex:Texture = Texture.fromTexture(sourcetexture, new Rectangle(i * 96, j * 96, 96, 96));
+ var t:Image = new Image(tiletex);
+ t.textureSmoothing = TextureSmoothing.NONE;
+ t.touchable = false;
tele.push(t);
}
}
public function drawmobilebutton(game:gameclass, xp:int, yp:int, wp:int, hp:int, t:String, cr:int, cg:int, cb:int, xoff:int = -8, yoff:int = -10):void {
- xp = xp + xoff;
+ xp = xp + xoff;
yp = yp + yoff;
drawfillrect(xp + 4, yp + 4, wp, hp, cr * 0.25, cg * 0.25, cb * 0.25);
drawfillrect(xp, yp, wp, hp, cr, cg, cb);
@@ -827,51 +851,7 @@
}
public function drawlevelmenu(game:gameclass, cr:int, cg:int, cb:int, division:int = 30):void {
- for (var i:int = 0; i < game.nummenuoptions; i++){
- if (i == game.currentmenuoption){
- if(game.nummenuoptions-i<=2){
- //Draw it highlighted
- if (game.menuoptionsactive[i]) {
- tempstring = game.menuoptions[i]; tempstring = "[ " + tempstring.toUpperCase() + " ]";
- print(110 + (i * division) - 16 +game.menuxoff, 140 + 8 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb);
- }else{
- tempstring = game.menuoptions[i];
- tempstring = "[ " + tempstring + " ]";
- //Draw it in gray
- print(110 + (i * division) - 16 +game.menuxoff, 140 + 8 + (i * 12) + game.menuyoff, tempstring, 128, 128, 128);
- }
- }else{
- //Draw it highlighted
- if (game.menuoptionsactive[i]){
- tempstring = game.menuoptions[i]; tempstring = "[ " + tempstring.toUpperCase() + " ]";
- print(110 + (i * division) - 16 +game.menuxoff, 140 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb);
- }else{
- tempstring = game.menuoptions[i];
- tempstring = "[ " + tempstring + " ]";
- //Draw it in gray
- print(110 + (i * division) - 16 +game.menuxoff, 140 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128);
- }
- }
- }else{
- if(game.nummenuoptions-i<=2){
- //Draw it normally
- if (game.menuoptionsactive[i]){
- print(110 + (i * division) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i], cr, cg, cb);
- }else{
- //Draw it in gray
- print(110 + (i * division) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i], 128, 128, 128);
- }
- }else{
- //Draw it normally
- if (game.menuoptionsactive[i]){
- print(110 + (i * division) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i], cr, cg, cb);
- }else{
- //Draw it in gray
- print(110 + (i * division) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i], 128, 128, 128);
- }
- }
- }
- }
+ trace("dwgfx.drawlevelmenu() is not implemented yet");
}
//Fade functions
@@ -907,16 +887,14 @@
public function drawfade():void {
if (fademode == 1) {
- backbuffer.fillRect(backbuffer.rect, 0x000000);
+ cls(0x000000);
}else if(fademode==3){
for (i = 0; i < 15; i++) {
- setmadrect(fadebars[i], i * 16, fadeamount, 16);
- backbuffer.fillRect(madrect, 0x000000);
+ drawfillrect(fadebars[i], i * 16, fadeamount, 16, 0, 0, 0);
}
}else if(fademode==5){
for (i = 0; i < 15; i++) {
- setmadrect(fadebars[i]-fadeamount, i * 16, 500, 16);
- backbuffer.fillRect(madrect, 0x000000);
+ drawfillrect(fadebars[i]-fadeamount, i * 16, 500, 16, 0, 0, 0);
}
}
}
@@ -941,7 +919,7 @@
m = ntextbox; ntextbox++;
}
- if(m<20){
+ if (m < 20) {
textbox[m].clear();
textbox[m].line[0] = t;
textbox[m].xp = xp;
@@ -1019,8 +997,7 @@
public function drawtextbox(x:int, y:int, w:int, h:int, r:int, g:int, b:int):void {
//given these parameters, draw a textbox
- madrect.x = x; madrect.y = y; madrect.width = w*8; madrect.height = h*8;
- backbuffer.fillRect(madrect, RGB(r / 6, g / 6, b / 6));
+ drawfillrect(x, y, w * 8, h * 8, r / 6, g / 6, b / 6);
drawcoloredtile(x, y, 40, r, g, b);
drawcoloredtile(x + (w*8) - 8, y, 42, r, g, b);
drawcoloredtile(x, y + (h*8) - 8, 45, r, g, b);
@@ -1037,10 +1014,9 @@
}
}
- public function drawpixeltextbox(x:int, y:int, w:int, h:int, w2:int, h2:int, r:int, g:int, b:int, xo:int=0, yo:int=0):void {
+ public function drawpixeltextbox(x:int, y:int, w:int, h:int, w2:int, h2:int, r:int, g:int, b:int, xo:int = 0, yo:int = 0):void {
//given these parameters, draw a textbox with a pixel width
- madrect.x = x; madrect.y = y; madrect.width = w; madrect.height = h;
- backbuffer.fillRect(madrect, RGB(r / 6, g / 6, b / 6));
+ drawfillrect(x, y, w, h, r / 6, g / 6, b / 6);
for (k = 0; k < w2-2; k++) {
drawcoloredtile(x + 8-xo + (k * 8), y, 41, r, g, b);
@@ -1058,13 +1034,9 @@
drawcoloredtile(x + (w) - 8, y + (h) - 8, 47, r, g, b);
}
- public function drawcustompixeltextbox(x:int, y:int, w:int, h:int, w2:int, h2:int, r:int, g:int, b:int, xo:int=0, yo:int=0):void {
+ public function drawcustompixeltextbox(x:int, y:int, w:int, h:int, w2:int, h2:int, r:int, g:int, b:int, xo:int = 0, yo:int = 0):void {
//given these parameters, draw a textbox with a pixel width
-
- //madrect.x = x; madrect.y = y; madrect.w = w; madrect.h = h;
- //backbuffer.fillRect(madrect, RGB(r / 6, g / 6, b / 6));
- madrect.x = x; madrect.y = y; madrect.width = w; madrect.height = h;
- backbuffer.fillRect(madrect, RGB(r / 6, g / 6, b / 6));
+ drawfillrect(x, y, w, h, r / 6, g / 6, b / 6);
for (k = 0; k < w2-2; k++){
drawcoloredtile(x + 8-xo + (k * 8), y, 41, r, g, b);
@@ -1092,34 +1064,67 @@
drawcoloredtile(x + (w) - 8, y + (h) - 8, 47, r, g, b);
}
- public function drawpartimage(t:int, xp:int, yp:int, wp:int, hp:int):void {
- tpoint.x = xp; tpoint.y = yp;
- madrect.x = 0; madrect.y = 0; madrect.width = wp; madrect.height = hp;
+ public var subtex:Texture;
+ public var subimage:Image;
+ public function drawpartimage(t:Texture, xp:int, yp:int, wp:int, hp:int):void {
+ // Acquire SubTexture and build an Image from it.
+ trect.x = 0;
+ trect.y = 0;
+ trect.width = wp;
+ trect.height = hp;
- backbuffer.copyPixels(images[t], madrect, tpoint);
+ if (subtex == null) {
+ subtex = Texture.fromTexture(t, trect);
+ subimage = new Image(subtex); // alloc. avoidable with pooling?
+ subimage.touchable = false;
+ subimage.textureSmoothing = TextureSmoothing.NONE;
+
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(subimage, tposition);
+ return;
+ }else {
+ //dispose of the old one
+ //No memory leaks, but this is throwing away a texture every call, which might
+ //get expensive? Ideally you'd reuse an image here if it hasn't changed.
+ //Or, maybe easier, make a function that grabs the chunk we need and keeps it somewhere
+ //else, hardcoding around the problem. Let's see if this is a problem in practice, though.
+ subtex.dispose();
+ subimage.dispose();
+
+ subtex = Texture.fromTexture(t, trect);
+ subimage = new Image(subtex);
+ subimage.touchable = false;
+ subimage.textureSmoothing = TextureSmoothing.NONE;
+
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(subimage, tposition);
+ return;
+ }
}
public function cutscenebars():void {
if (showcutscenebars) {
cutscenebarspos += 25;
if (cutscenebarspos >= 360) cutscenebarspos = 360;
- setmadrect(0, 0, cutscenebarspos, 16);
- backbuffer.fillRect(madrect, 0x000000);
- setmadrect(360-cutscenebarspos, 224, cutscenebarspos, 16);
- backbuffer.fillRect(madrect, 0x000000);
+ drawfillrect(0, 0, cutscenebarspos, 16, 0, 0, 0);
+ drawfillrect(360 - cutscenebarspos, 224, cutscenebarspos, 16, 0, 0, 0);
}else {
//disappearing
if (cutscenebarspos > 0) {
cutscenebarspos -= 25;
- //draw
- setmadrect(0, 0, cutscenebarspos, 16);
- backbuffer.fillRect(madrect, 0x000000);
- setmadrect(360-cutscenebarspos, 224, cutscenebarspos, 16);
- backbuffer.fillRect(madrect, 0x000000);
+ //draw
+ drawfillrect(0, 0, cutscenebarspos, 16, 0, 0, 0);
+ drawfillrect(360 - cutscenebarspos, 224, cutscenebarspos, 16, 0, 0, 0);
}
}
}
+ //For android: this function draws textboxes to a buffer first, where they're later copied to the screen
+ //buffer is a 320x500 image. X coordinates aren't changed, but y coordinates are
+ public var textbox_ybuffer:int;
+ public var textbox_ybufferheight:int = 0;
public function drawgui(help:helpclass):void {
textboxcleanup();
//Draw all the textboxes to the screen
@@ -1137,8 +1142,8 @@
print(textbox[i].xp + 8, textbox[i].yp + 8 + (j * 8), textbox[i].line[j], 196, 196, 255 - help.glow);
}
}
- }else{
- backbuffer.fillRect(textbox[i].textrect, RGB(textbox[i].r/6, textbox[i].g/6, textbox[i].b / 6));
+ }else {
+ drawfillrect(textbox[i].textrect.x, textbox[i].textrect.y, textbox[i].textrect.width, textbox[i].textrect.height, textbox[i].r/6, textbox[i].g/6, textbox[i].b / 6);
drawcoloredtile(textbox[i].xp, textbox[i].yp, 40, textbox[i].r, textbox[i].g, textbox[i].b);
drawcoloredtile(textbox[i].xp+textbox[i].w-8, textbox[i].yp, 42, textbox[i].r, textbox[i].g, textbox[i].b);
@@ -1223,111 +1228,258 @@
return (blue | (green << 8) | (red << 16))
}
- public function addmobileimage():void {
- var t:BitmapData = new BitmapData(buffer.width, buffer.height, true, 0x000000);
- setmadrect(0, 0, buffer.width, buffer.height);
- t.copyPixels(buffer, madrect, tl);
+ public function addmobileimage(imgname:String):void {
+ var sourcetexture:Texture = starlingassets.getTexture(imgname);
+ var t:Image = new Image(sourcetexture);
+ t.touchable = false;
+ t.textureSmoothing = TextureSmoothing.NONE;
mobileimages.push(t);
}
- public function addimage():void {
- var t:BitmapData = new BitmapData(buffer.width, buffer.height, true, 0x000000);
- setmadrect(0, 0, buffer.width, buffer.height);
- t.copyPixels(buffer, madrect, tl);
+ public function addimage(imgname:String):void {
+ var sourcetexture:Texture = starlingassets.getTexture(imgname);
+ var t:Image = new Image(sourcetexture);
+ t.touchable = false;
+ t.textureSmoothing = TextureSmoothing.NONE;
images.push(t);
}
- public function addplayerlevelimage():void {
- var t:BitmapData = new BitmapData(buffer.width, buffer.height, true, 0x000000);
- setmadrect(0, 0, buffer.width, buffer.height);
- t.copyPixels(buffer, madrect, tl);
+ public function addimage_rendertexture(imgname:String):void {
+ customminimap = starlingassets.getTexture(imgname) as RenderTexture;
+ var t:Image = new Image(customminimap);
+ t.touchable = false;
+ t.textureSmoothing = TextureSmoothing.NONE;
+ images.push(t);
+ }
+
+ public function addplayerlevelimage(imgname:String):void {
+ var sourcetexture:Texture = starlingassets.getTexture(imgname);
+ var t:Image = new Image(sourcetexture);
+ t.touchable = false;
+ t.textureSmoothing = TextureSmoothing.NONE;
playerlevelimages.push(t);
}
- public function addbackground():void {
- var t:BitmapData = new BitmapData(160, 144, true, 0x000000);
- t.copyPixels(buffer, bg_rect, tl);
+ public function addbackground(imgname:String):void {
+ //Don't think this is actually used in VVVVVV
+ var sourcetexture:Texture = starlingassets.getTexture(imgname);
+ var t:Image = new Image(sourcetexture);
+ t.touchable = false;
+ t.textureSmoothing = TextureSmoothing.NONE;
backgrounds.push(t);
}
+ public var towerx_pix:int;
+ public var towery_pix:int;
+ public var tower_bgcol:Vector. = new Vector.;
+ public var tower_bgdarkcol:Vector. = new Vector.;
+ public var lasttowercolstate:int = -1;
+ public var lasttowercolstate_front:int = -1;
+ public var maptdrawfront:Boolean = true;
+ public var forcetowerupdate:int = 10;
+ public var forcefronttowerupdate:int = 10;
+ public var towerfront_lastypos:int = 0;
+ public var tower_lastypos:int = 0;
+
+ public var forcewarpzonehorizontalupdate:int = 2;
+ public var forcewarpzoneverticalupdate:int = 1;
+ public var forcetowerstaticupdate:int = 1;
+
+ public function forcescreenupdates():void {
+ if (forcetowerupdate < 3) forcetowerupdate = 3;
+ if (forcefronttowerupdate < 3) forcefronttowerupdate = 3;
+ if (forcetowerstaticupdate < 3) forcetowerstaticupdate = 3;
+ if (forcewarpzoneverticalupdate < 1) forcewarpzoneverticalupdate = 1;
+ if (forcewarpzonehorizontalupdate < 1) forcewarpzonehorizontalupdate = 1;
+ }
+
public function drawtowerbackground(map:mapclass):void {
- if (map.bypos < 0) map.bypos += 120 * 8;
+ if (map.bypos < 0) {
+ map.bypos += 120 * 8;
+ forcetowerupdate += 5;
+ }
- if (map.scrolldir == 1) map.tdrawback = true;
-
- if (map.tdrawback) {
- //Draw the whole thing; needed for every colour cycle!
- for (j = 0; j < 30; j++) {
- for (i = 0; i < 40; i++) {
- temp = map.tower.backat(i, j, map.bypos);
- drawtowertile3(i * 8, (j * 8) - (map.bypos % 8), temp, map.colstate);
+ if (map.scrolldir == 1) {
+ if (map.tdrawback || lasttowercolstate != map.colstate || forcetowerupdate > 0) {
+ //Draw the whole thing; needed for every colour cycle!
+ towerbufferbackground_meshbatch.y = 0;
+ tower_lastypos = map.bypos;
+
+ towerbufferbackground_meshbatch.clear();
+ //Draw the whole thing; needed for every colour cycle!
+ for (j = 0; j < 40; j++) {
+ for (i = 0; i < 40; i++) {
+ temp = map.tower.backat(i, j, map.bypos);
+ drawtowertile3(i * 8, (j * 8) - (map.bypos % 8), temp, map.colstate);
+ }
+ }
+
+ backbuffer.draw(towerbufferbackground_meshbatch);
+
+ map.tdrawback = false;
+ lasttowercolstate = map.colstate;
+ if (forcetowerupdate > 0) forcetowerupdate--;
+ }else {
+ //just scroll down a bit
+ towerbufferbackground_meshbatch.y = -int(map.bypos - tower_lastypos);
+ backbuffer.draw(towerbufferbackground_meshbatch);
+
+ if (towerbufferbackground_meshbatch.y < -80) {
+ towerbufferbackground_meshbatch.y = 0;
+ map.tdrawback = true;
}
}
-
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl, null, null, false);
-
- map.tdrawback = false;
- }else {
- //just update the bottom
- towerbuffer.scroll(0, -map.bscroll);
- for (i = 0; i < 40; i++) {
- temp = map.tower.backat(i, 0, map.bypos);
- drawtowertile3(i * 8, -(map.bypos % 8), temp, map.colstate);
+ }else{
+ if (map.tdrawback || lasttowercolstate != map.colstate || forcetowerupdate > 0) {
+ //Draw the whole thing; needed for every colour cycle!
+ towerbufferbackground_meshbatch.y = 0;
+ tower_lastypos = map.bypos;
+
+ towerbufferbackground_meshbatch.clear();
+ //Draw the whole thing; needed for every colour cycle!
+ for (j = -10; j < 30; j++) {
+ for (i = 0; i < 40; i++) {
+ temp = map.tower.backat(i, j, map.bypos);
+ drawtowertile3(i * 8, (j * 8) - (map.bypos % 8), temp, map.colstate);
+ }
+ }
+
+ backbuffer.draw(towerbufferbackground_meshbatch);
+
+ map.tdrawback = false;
+ lasttowercolstate = map.colstate;
+ if (forcetowerupdate > 0) forcetowerupdate--;
+ }else {
+ //just scroll down a bit
+ towerbufferbackground_meshbatch.y = -int(map.bypos - tower_lastypos);
+ backbuffer.draw(towerbufferbackground_meshbatch);
+
+ if (towerbufferbackground_meshbatch.y > 80) {
+ towerbufferbackground_meshbatch.y = 0;
+ map.tdrawback = true;
+ }
}
-
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl, null, null, false);
}
}
public function drawtowerbackgroundsolo(map:mapclass):void {
- if (map.bypos < 0) map.bypos += 120 * 8;
+ if (map.bypos < 0) {
+ map.bypos += 120 * 8;
+ forcetowerupdate += 5;
+ }
- if (map.tdrawback) {
+ if (map.scrolldir == 1) map.tdrawback = true;
+
+ if (map.tdrawback || lasttowercolstate != map.colstate || forcetowerupdate > 0) {
//Draw the whole thing; needed for every colour cycle!
- for (j = 0; j < 31; j++) {
+ towerbufferbackground_meshbatch.y = 0;
+ tower_lastypos = map.bypos;
+
+ towerbufferbackground_meshbatch.clear();
+ //Draw the whole thing; needed for every colour cycle!
+ for (j = -10; j < 31; j++) {
for (i = 0; i < 40; i++) {
temp = map.tower.backat(i, j, map.bypos);
drawtowertile3(i * 8, (j * 8) - (map.bypos % 8), temp, map.colstate);
}
}
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl, null, null, false);
+ backbuffer.draw(towerbufferbackground_meshbatch);
map.tdrawback = false;
+ lasttowercolstate = map.colstate;
+ if (forcetowerupdate > 0) forcetowerupdate--;
}else {
- //just update the bottom
- towerbuffer.scroll(0, -map.bscroll);
- for (i = 0; i < 40; i++) {
- temp = map.tower.backat(i, 0, map.bypos);
- drawtowertile3(i * 8, -(map.bypos % 8), temp, map.colstate);
- }
+ //just scroll down a bit
+ towerbufferbackground_meshbatch.y = -int(map.bypos - tower_lastypos);
+ backbuffer.draw(towerbufferbackground_meshbatch);
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl, null, null, false);
+ if (towerbufferbackground_meshbatch.y > 80) {
+ towerbufferbackground_meshbatch.y = 0;
+ map.tdrawback = true;
+ }
}
}
- public function drawtowermap(map:mapclass):void {
- for (j = 0; j < 30; j++) {
- for (i = 0; i < 40; i++) {
- temp = map.tower.at(i, j, map.ypos);
- if (temp > 0) drawtile3(i * 8, (j * 8) - (map.ypos % 8), temp, map.colstate);
+ public function drawtowermap(game:gameclass, map:mapclass):void {
+ if (game.deathseq > 0) { forcefronttowerupdate = 20; }
+
+ if (map.scrolldir == 1) {
+ if (maptdrawfront || lasttowercolstate_front != map.colstate || forcefronttowerupdate > 0) {
+ towerbufferforeground_meshbatch.y = 0;
+ towerfront_lastypos = map.ypos;
+ towerbufferforeground_meshbatch.clear();
+
+ for (j = 0; j < 40; j++) {
+ for (i = 0; i < 40; i++) {
+ temp = map.tower.at(i, j, map.ypos);
+ if (temp > 0) drawtile3_batch(i * 8, (j * 8) - (map.ypos % 8), temp, map.colstate);
+ }
+ }
+
+ backbuffer.draw(towerbufferforeground_meshbatch);
+
+ maptdrawfront = false;
+ lasttowercolstate_front = map.colstate;
+ if (forcefronttowerupdate > 0) forcefronttowerupdate--;
+ }else {
+ //just scroll down a bit
+ towerbufferforeground_meshbatch.y = -int(map.ypos - towerfront_lastypos);
+ backbuffer.draw(towerbufferforeground_meshbatch);
+
+ if (towerbufferforeground_meshbatch.y < -80) {
+ towerbufferforeground_meshbatch.y = 0;
+ maptdrawfront = true;
+ }
+ }
+ }else{
+ if (maptdrawfront || lasttowercolstate_front != map.colstate || forcefronttowerupdate > 0) {
+ towerbufferforeground_meshbatch.y = 0;
+ towerfront_lastypos = map.ypos;
+ towerbufferforeground_meshbatch.clear();
+
+ for (j = -10; j < 30; j++) {
+ for (i = 0; i < 40; i++) {
+ temp = map.tower.at(i, j, map.ypos);
+ if (temp > 0) drawtile3_batch(i * 8, (j * 8) - (map.ypos % 8), temp, map.colstate);
+ }
+ }
+
+ backbuffer.draw(towerbufferforeground_meshbatch);
+
+ maptdrawfront = false;
+ lasttowercolstate_front = map.colstate;
+ if (forcefronttowerupdate > 0) forcefronttowerupdate--;
+ }else {
+ //just scroll down a bit
+ towerbufferforeground_meshbatch.y = -int(map.ypos - towerfront_lastypos);
+ backbuffer.draw(towerbufferforeground_meshbatch);
+
+ if (towerbufferforeground_meshbatch.y > 80) {
+ towerbufferforeground_meshbatch.y = 0;
+ maptdrawfront = true;
+ }
}
}
}
public function drawtowermap_nobackground(map:mapclass):void {
+ towerbufferforeground_meshbatch.clear();
+
for (j = 0; j < 30; j++) {
for (i = 0; i < 40; i++) {
temp = map.tower.at(i, j, map.ypos);
- if (temp > 0 && temp<28) drawtile3(i * 8, (j * 8) - (map.ypos % 8), temp, map.colstate);
+ if (temp > 0 && temp<28) drawtile3_batch(i * 8, (j * 8) - (map.ypos % 8), temp, map.colstate);
}
}
+
+ backbuffer.draw(towerbufferforeground_meshbatch);
}
public function drawtowerspikes(map:mapclass):void {
for (i = 0; i < 40; i++) {
- drawtile3(i * 8, -8+map.spikeleveltop, 9, map.colstate);
- drawtile3(i * 8, 230-map.spikelevelbottom, 8, map.colstate);
+ drawtile3(i * 8, -8 + map.spikeleveltop, 9, map.colstate);
+ drawtile3(i * 8, 230 - map.spikelevelbottom, 8, map.colstate);
}
}
@@ -1345,39 +1497,53 @@
for (var i:int = 0; i < obj.nentity; i++) {
if (!obj.entities[i].invis && obj.entities[i].active) {
if (obj.entities[i].size == 0) { // Sprites
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp-map.ypos;
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp, obj.entities[i].yp - map.ypos);
+
setcol(obj.entities[i].colour, help);
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
//screenwrapping!
if (!map.minitowermode) {
if ( map.ypos >= 500 && map.ypos <= 5000) { //The "wrapping" area of the tower
if (tpoint.x < 0) {
- tpoint.x += 320;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp + 320, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
if (tpoint.x > 300) {
- tpoint.x -= 320;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp - 320, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
}
}
- }else if (obj.entities[i].size == 1) { // Tiles
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp-map.ypos;
- backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
+ }else if (obj.entities[i].size == 1) { // Tiles
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
}else if (obj.entities[i].size == 2) { // Special: Moving platform, 4 tiles
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp-map.ypos;
- backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp + 8, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp + 16, obj.entities[i].yp - map.ypos);
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+
+ tposition.identity();
+ tposition.translate(obj.entities[i].xp + 24, obj.entities[i].yp - map.ypos);
}else if (obj.entities[i].size == 3) { // Big chunky pixels!
prect.x = obj.entities[i].xp; prect.y = obj.entities[i].yp-map.ypos;
//A seperate index of colours, for simplicity
- if(obj.entities[i].colour==1){
- backbuffer.fillRect(prect, RGB(196 - (Math.random() * 64), 10, 10));
+ if (obj.entities[i].colour == 1) {
+ drawfillrect(prect.x, prect.y, prect.width, prect.height, 196 - (Math.random() * 64), 10, 10);
}else if (obj.entities[i].colour == 2) {
- backbuffer.fillRect(prect, RGB(160- help.glow/2 - (Math.random()*20), 200- help.glow/2, 220 - help.glow));
+ drawfillrect(prect.x, prect.y, prect.width, prect.height, 160- help.glow/2 - (Math.random()*20), 200- help.glow/2, 220 - help.glow);
}
}else if (obj.entities[i].size == 4) { // Small pickups
drawhuetile(obj.entities[i].xp, obj.entities[i].yp-map.ypos, obj.entities[i].tile, obj.entities[i].colour);
@@ -1397,24 +1563,25 @@
public function drawbackground(t:int, map:mapclass):void {
switch(t) {
case 1:
- //Starfield
- backbuffer.fillRect(backbuffer.rect, 0x000000);
+ //Starfield
+ drawfillrect(0, 0, 320, 240, 0, 0, 0);
for (i = 0; i < 50; i++) {
if (starsspeed[i] <= 6) {
- backbuffer.fillRect(stars[i], 0x222222);
+ drawfillrect(stars[i].x, stars[i].y, stars[i].width, stars[i].height, 34, 34, 34);
}else {
- backbuffer.fillRect(stars[i], 0x555555);
+ drawfillrect(stars[i].x, stars[i].y, stars[i].width, stars[i].height, 85, 85, 85);
}
stars[i].x -= starsspeed[i];
if (stars[i].x < -10) {
stars[i].x += 340;
stars[i].y = Math.random() * 240;
- starsspeed[i] = 4+(Math.random()*4);
+ starsspeed[i] = 4 + (Math.random()*4);
}
}
break;
case 2:
- //Lab
+ //Lab
+ i = 0;
switch(rcol) {
//Akward ordering to match tileset
case 0: bcol2 = RGB(0, 16*backboxint[i], 16*backboxint[i]); break; //Cyan
@@ -1432,7 +1599,7 @@
if (spcol >= 12) spcol = 0;
}
switch(spcol) {
- case 0: bcol2 = RGB(0, 16*backboxint[i], 16*backboxint[i]); break; //Cyan
+ case 0: bcol2 = RGB(0, 16 * backboxint[i], 16 * backboxint[i]); break; //Cyan
case 1: bcol2 = RGB(0, (spcoldel+1)*backboxint[i], 16*backboxint[i]); break; //Cyan
case 2: bcol2 = RGB(0, 0, 16*backboxint[i]); break; //Blue
case 3: bcol2 = RGB((16-spcoldel)*backboxint[i], 0, 16*backboxint[i]); break; //Blue
@@ -1447,7 +1614,7 @@
}
break;
}
- backbuffer.fillRect(backbuffer.rect, bcol2);
+ cls(bcol2);
for (i = 0; i < 18; i++) {
switch(rcol) {
//Akward ordering to match tileset
@@ -1475,11 +1642,11 @@
}
break;
}
- backbuffer.fillRect(backboxes[i], bcol);
+ drawfillrect(backboxes[i].x, backboxes[i].y, backboxes[i].width, backboxes[i].height, bcol);
backboxrect.x = backboxes[i].x + 1; backboxrect.y = backboxes[i].y + 1;
backboxrect.width = backboxes[i].width - 2; backboxrect.height = backboxes[i].height - 2;
- backbuffer.fillRect(backboxrect, bcol2);
+ drawfillrect(backboxrect.x, backboxrect.y, backboxrect.width, backboxrect.height, bcol2);
backboxes[i].x += backboxvx[i];
backboxes[i].y += backboxvy[i];
@@ -1490,67 +1657,65 @@
}
break;
case 3: //Warp zone (horizontal)
- backoffset+=3; if (backoffset >= 16) backoffset -= 16;
+ backoffset += 3; if (backoffset >= 16) backoffset -= 16;
- if (backgrounddrawn) {
- towerbuffer.scroll( -3, 0);
+ if (forcewarpzonehorizontalupdate > 0) {
+ warpzonehorizontal_meshbatch.x = 0;
+ warpzonehorizontal_meshbatch.clear();
for (j = 0; j < 15; j++) {
- temp = 680 + (rcol * 3);
- drawtowertile(317 - backoffset, (j * 16), temp+40); //20*16 = 320
- drawtowertile(317 - backoffset + 8, (j * 16), temp + 41);
- drawtowertile(317 - backoffset, (j * 16) + 8, temp + 80);
- drawtowertile(317 - backoffset + 8, (j * 16) + 8, temp + 81);
- }
- }else {
- //draw the whole thing for the first time!
- backoffset = 0;
- towerbuffer.fillRect(towerbuffer.rect, 0x000000);
- for (j = 0; j < 15; j++) {
- for (i = 0; i < 21; i++) {
+ for (i = -1; i < 21; i++) {
temp = 680 + (rcol * 3);
- drawtowertile((i * 16) - backoffset, (j * 16), temp+40);
- drawtowertile((i * 16) - backoffset + 8, (j * 16), temp + 41);
- drawtowertile((i * 16) - backoffset, (j * 16) + 8, temp + 80);
- drawtowertile((i * 16) - backoffset + 8, (j * 16) + 8, temp + 81);
+ tposition.identity(); tposition.translate(int((i * 16) - backoffset), int(j * 16));
+ warpzonehorizontal_meshbatch.addMesh(tiles2[temp+40], tposition);
+ tposition.identity(); tposition.translate(int((i * 16) - backoffset + 8), int((j * 16)));
+ warpzonehorizontal_meshbatch.addMesh(tiles2[temp + 41], tposition);
+ tposition.identity(); tposition.translate(int((i * 16) - backoffset), int((j * 16) + 8));
+ warpzonehorizontal_meshbatch.addMesh(tiles2[temp + 80], tposition);
+ tposition.identity(); tposition.translate(int((i * 16) - backoffset + 8), int((j * 16) + 8));
+ warpzonehorizontal_meshbatch.addMesh(tiles2[temp + 81], tposition);
}
}
- backgrounddrawn = true;
+
+ backbuffer.draw(warpzonehorizontal_meshbatch);
+ forcewarpzonehorizontalupdate--;
+ }else {
+ warpzonehorizontal_meshbatch.x = backoffset;
+ backbuffer.draw(warpzonehorizontal_meshbatch);
}
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl);
break;
case 4: //Warp zone (vertical)
- backoffset+=3; if (backoffset >= 16) backoffset -= 16;
+ backoffset += 3;
+ if (backoffset >= 16) backoffset -= 16;
- if (backgrounddrawn) {
- towerbuffer.scroll(0, -3);
- for (i = 0; i < 21; i++) {
- temp = 760 + (rcol * 3);
- drawtowertile((i * 16), 237 - backoffset, temp + 40); //14*17=240 - 3
- drawtowertile((i * 16) + 8, 237 - backoffset, temp + 41);
- drawtowertile((i * 16), 237 - backoffset + 8, temp + 80);
- drawtowertile((i * 16) + 8, 237 - backoffset + 8, temp + 81);
- }
- }else {
- //draw the whole thing for the first time!
- backoffset = 0;
- towerbuffer.fillRect(towerbuffer.rect, 0x000000);
- for (j = 0; j < 15; j++) {
+ if (forcewarpzoneverticalupdate > 0) {
+ warpzonevertical_meshbatch.y = 0;
+ warpzonevertical_meshbatch.clear();
+ for (j = -1; j < 16; j++) {
for (i = 0; i < 21; i++) {
temp = 760 + (rcol * 3);
- drawtowertile((i * 16), (j * 16)- backoffset, temp+40);
- drawtowertile((i * 16)+ 8, (j * 16)- backoffset, temp + 41);
- drawtowertile((i * 16), (j * 16)- backoffset + 8, temp + 80);
- drawtowertile((i * 16)+ 8, (j * 16)- backoffset + 8, temp + 81);
+ tposition.identity(); tposition.translate(int((i * 16)), int((j * 16) - backoffset));
+ warpzonevertical_meshbatch.addMesh(tiles2[temp+40], tposition);
+ tposition.identity(); tposition.translate(int((i * 16) + 8), int((j * 16) - backoffset));
+ warpzonevertical_meshbatch.addMesh(tiles2[temp + 41], tposition);
+ tposition.identity(); tposition.translate(int((i * 16)), int((j * 16) - backoffset + 8));
+ warpzonevertical_meshbatch.addMesh(tiles2[temp + 80], tposition);
+ tposition.identity(); tposition.translate(int((i * 16) + 8), int((j * 16) - backoffset + 8));
+ warpzonevertical_meshbatch.addMesh(tiles2[temp + 81], tposition);
}
}
- backgrounddrawn = true;
+
+ backbuffer.draw(warpzonevertical_meshbatch);
+ forcewarpzoneverticalupdate--;
+ }else {
+ warpzonevertical_meshbatch.y = backoffset;
+ backbuffer.draw(warpzonevertical_meshbatch);
}
- backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl);
+ //backbuffer.copyPixels(towerbuffer, towerbuffer.rect, tl);
break;
case 5:
- //Warp zone, central
+ //Warp zone, central
switch(rcol) {
//Akward ordering to match tileset
case 0: warpbcol = 0x0A100E; warpfcol = 0x102221; break; //Cyan
@@ -1568,24 +1733,24 @@
warpskip = (warpskip + 1) % 2;
}
- for (i = 10 ; i >= 0; i--) {
+ for (i = 10; i >= 0; i--) {
temp = (i << 4) + backoffset;
setwarprect(160 - temp, 120 - temp, temp * 2, temp * 2);
if (i % 2 == warpskip) {
- backbuffer.fillRect(warprect, warpbcol);
+ drawfillrect(warprect.x, warprect.y, warprect.width, warprect.height, warpbcol);
}else {
- backbuffer.fillRect(warprect, warpfcol);
+ drawfillrect(warprect.x, warprect.y, warprect.width, warprect.height, warpfcol);
}
}
break;
case 6:
//Final Starfield
- backbuffer.fillRect(backbuffer.rect, 0x000000);
+ cls(0x000000);
for (i = 0; i < 50; i++) {
if (starsspeed[i] <= 8) {
- backbuffer.fillRect(stars[i], 0x222222);
+ drawfillrect(stars[i].x, stars[i].y, stars[i].width, stars[i].height, 0x222222);
}else {
- backbuffer.fillRect(stars[i], 0x555555);
+ drawfillrect(stars[i].x, stars[i].y, stars[i].width, stars[i].height, 0x555555);
}
stars[i].y -= starsspeed[i];
if (stars[i].y < -10) {
@@ -1597,71 +1762,118 @@
break;
case 7:
//Static, unscrolling section of the tower
- for (j = 0; j < 30; j++) { for (i = 0; i < 40; i++) { drawtile3(i * 8, j * 8, map.tower.backat(i, j, 200), 15); } }
+ if (forcetowerstaticupdate > 0) {
+ towerbufferstatic_meshbatch.clear();
+
+ for (j = 0; j < 30; j++) {
+ for (i = 0; i < 40; i++) {
+ tposition.identity();
+ tposition.translate(int(i * 8), int(j * 8));
+ towerbufferstatic_meshbatch.addMesh(tiles3[map.tower.backat(i, j, 200) + (15 * 30)], tposition);
+ }
+ }
+
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ forcetowerstaticupdate--;
+ }else {
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ }
break;
case 8:
//Static, unscrolling section of the tower
- for (j = 0; j < 30; j++) { for (i = 0; i < 40; i++) { drawtile3(i * 8, j * 8, map.tower.backat(i, j, 200), 10); } }
+ if (forcetowerstaticupdate > 0) {
+ towerbufferstatic_meshbatch.clear();
+
+ for (j = 0; j < 30; j++) {
+ for (i = 0; i < 40; i++) {
+ tposition.identity();
+ tposition.translate(int(i * 8), int(j * 8));
+ towerbufferstatic_meshbatch.addMesh(tiles3[map.tower.backat(i, j, 200) + (15 * 10)], tposition);
+ }
+ }
+
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ forcetowerstaticupdate--;
+ }else {
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ }
break;
case 9:
//Static, unscrolling section of the tower
- for (j = 0; j < 30; j++) { for (i = 0; i < 40; i++) { drawtile3(i * 8, j * 8, map.tower.backat(i, j, 600), 0); } }
+ if (forcetowerstaticupdate > 0) {
+ towerbufferstatic_meshbatch.clear();
+
+ for (j = 0; j < 30; j++) {
+ for (i = 0; i < 40; i++) {
+ tposition.identity();
+ tposition.translate(int(i * 8), int(j * 8));
+ towerbufferstatic_meshbatch.addMesh(tiles3[map.tower.backat(i, j, 600)], tposition);
+ }
+ }
+
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ forcetowerstaticupdate--;
+ }else {
+ backbuffer.draw(towerbufferstatic_meshbatch);
+ }
break;
default:
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- //backbuffer.copyPixels(backgrounds[t], bg_rect, tl);
+ drawfillrect(0, 0, 320, 240, 0, 0, 0);
break;
}
}
+ public function textbox_drawimage(t:int, xp:int, yp:int, cent:Boolean=false):void {
+ trace("dwgfx.textbox_drawimage() is not implemented yet");
+ }
+
public function drawimage(t:int, xp:int, yp:int, cent:Boolean=false):void {
if (cent) {
- tpoint.x = 160 - int(images[t].width / 2); tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = images[t].width; trect.height = images[t].height;
- backbuffer.copyPixels(images[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(160 - int(images[t].width / 2), yp);
+ backbuffer.draw(images[t], tposition);
}else {
- tpoint.x = xp; tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = images[t].width; trect.height = images[t].height;
- backbuffer.copyPixels(images[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(images[t], tposition);
}
}
public function drawmobileimage(t:int, xp:int, yp:int, cent:Boolean=false):void {
if (cent) {
- tpoint.x = 160 - int(mobileimages[t].width / 2); tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = mobileimages[t].width; trect.height = mobileimages[t].height;
- backbuffer.copyPixels(mobileimages[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(160 - int(mobileimages[t].width / 2), yp);
+ backbuffer.draw(mobileimages[t], tposition);
}else {
- tpoint.x = xp; tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = mobileimages[t].width; trect.height = mobileimages[t].height;
- backbuffer.copyPixels(mobileimages[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(mobileimages[t], tposition);
}
}
public function drawmobilehands(t:int, xp:int, yp:int):void {
- tpoint.x = xp; tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = mobileimages[t].width; trect.height = 70;
- backbuffer.copyPixels(mobileimages[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(mobileimages[t], tposition);
}
public function drawplayerlevelimage(t:int, xp:int, yp:int):void {
- tpoint.x = xp; tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = playerlevelimages[t].width; trect.height = playerlevelimages[t].height;
- backbuffer.copyPixels(playerlevelimages[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(xp, yp);
+ backbuffer.draw(playerlevelimages[t], tposition);
}
public function drawimagecol(t:int, xp:int, yp:int, r:int, g:int, b:int, cent:Boolean = false):void {
- setcolreal(RGB(r,g,b));
if (cent) {
- tpoint.x = 160 - int(images[t].width / 2); tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = images[t].width; trect.height = images[t].height;
- images[t].colorTransform(trect, ct);
- backbuffer.copyPixels(images[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(160 - int(images[t].width / 2), yp);
+ images[t].color = RGB(r, g, b);
+ backbuffer.draw(images[t], tposition);
}else {
- tpoint.x = xp; tpoint.y = yp;
- trect.x = 0; trect.y = 0; trect.width = images[t].width; trect.height = images[t].height;
- images[t].colorTransform(trect, ct);
- backbuffer.copyPixels(images[t], trect, tpoint);
+ tposition.identity();
+ tposition.translate(xp, yp);
+ images[t].color = RGB(r, g, b);
+ backbuffer.draw(images[t], tposition);
}
}
@@ -1677,7 +1889,7 @@
}
public function setcol(t:int, help:helpclass):void {
- //Setup predefinied colours as per our zany palette
+ //Setup predefinied colours as per our zany palette
switch(t) {
//Player Normal
case 0: ct.color = RGB(160- help.glow/2 - (Math.random()*20), 200- help.glow/2, 220 - help.glow); break;
@@ -1824,25 +2036,30 @@
public function setcolreal(t:int):void {
ct.color = t;
}
-
+
+ public function textbox_drawcoloredtile(x:int, y:int, t:int, r:int, g:int, b:int):void {
+ trace("dwgfx.textbox_drawcoloredtile() is not implemented yet");
+ }
+
public function drawcoloredtile(x:int, y:int, t:int, r:int, g:int, b:int):void {
- tpoint.x = x; tpoint.y = y;
- setcolreal(RGB(r,g,b));
- tiles[t].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[t], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+
+ tiles[t].color = RGB(r, g, b);
+ backbuffer.draw(tiles[t], tposition);
}
public function drawhuetile(x:int, y:int, t:int, c:int):void {
- tpoint.x = x; tpoint.y = y;
+ tposition.identity();
+ tposition.translate(x, y);
switch(c) {
- case 0:setcolreal(RGB(250-(Math.random()*32), 250-(Math.random()*32), 10)); break;
- case 1:setcolreal(RGB(250-(Math.random()*32), 250-(Math.random()*32), 10)); break;
+ case 0: tiles[t].color = RGB(250-(Math.random()*32), 250-(Math.random()*32), 10); break;
+ case 1: tiles[t].color = RGB(250-(Math.random()*32), 250-(Math.random()*32), 10); break;
- default:setcolreal(RGB(250-(Math.random()*32), 250-(Math.random()*32), 10)); break;
+ default: tiles[t].color = RGB(250-(Math.random()*32), 250-(Math.random()*32), 10); break;
}
- tiles[t].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[t], tiles_rect, tpoint);
+ backbuffer.draw(tiles[t], tposition);
}
public function drawcrewman(x:int, y:int, t:int, act:Boolean, help:helpclass, noshift:Boolean=false):void {
@@ -1945,42 +2162,32 @@
}
public function drawsprite(x:int, y:int, t:int, r:int, g:int, b:int):void {
- tpoint.x = x; tpoint.y = y;
- setcolreal(RGB(r,g,b));
- sprites[t].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[t], sprites_rect, tpoint);
+ sprites[t].color = RGB(r, g, b);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(sprites[t], tposition);
+ }
+
+ public function textbox_drawsprite(x:int, y:int, t:int, r:int, g:int, b:int):void {
+ trace("dwgfx.textbox_drawsprite() is not implemented yet");
}
public function drawgravityline(t:int, obj:entityclass):void {
if (obj.entities[t].life == 0) {
- /*
switch(linestate) {
- case 0: backbuffer.fillRect(line_rect, RGB(0, 200, 0)); break;
- case 1: backbuffer.fillRect(line_rect, RGB(16, 245, 0)); break;
- case 2: backbuffer.fillRect(line_rect, RGB(0, 245, 16)); break;
- case 3: backbuffer.fillRect(line_rect, RGB(16, 200, 0)); break;
- case 4: backbuffer.fillRect(line_rect, RGB(24, 255, 16)); break;
- case 5: backbuffer.fillRect(line_rect, RGB(16, 235, 0)); break;
- case 6: backbuffer.fillRect(line_rect, RGB(0, 164, 16)); break;
- case 7: backbuffer.fillRect(line_rect, RGB(16, 245, 24)); break;
- case 8: backbuffer.fillRect(line_rect, RGB(0, 255, 16)); break;
- case 9: backbuffer.fillRect(line_rect, RGB(96, 245, 96)); break;
- }
- */
- switch(linestate) {
- case 0: backbuffer.fillRect(line_rect, RGB(200 - 20, 200 - 20, 200 - 20)); break;
- case 1: backbuffer.fillRect(line_rect, RGB(225 - 30, 245 - 30, 245 - 30)); break;
- case 2: backbuffer.fillRect(line_rect, RGB(245 - 30, 245 - 30, 225 - 30)); break;
- case 3: backbuffer.fillRect(line_rect, RGB(164 - 10, 200 - 20, 200 - 20)); break;
- case 4: backbuffer.fillRect(line_rect, RGB(224 - 20, 255 - 30, 196 - 20)); break;
- case 5: backbuffer.fillRect(line_rect, RGB(205 - 20, 235 - 30, 196 - 20)); break;
- case 6: backbuffer.fillRect(line_rect, RGB(164 - 10, 164 - 10, 164 - 10)); break;
- case 7: backbuffer.fillRect(line_rect, RGB(225 - 30, 245 - 30, 205 - 20)); break;
- case 8: backbuffer.fillRect(line_rect, RGB(205 - 20, 255 - 30, 225 - 30)); break;
- case 9: backbuffer.fillRect(line_rect, RGB(245 - 30, 245 - 30, 245 - 30)); break;
+ case 0: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 200 - 20, 200 - 20, 200 - 20); break;
+ case 1: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 225 - 30, 245 - 30, 245 - 30); break;
+ case 2: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 245 - 30, 245 - 30, 225 - 30); break;
+ case 3: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 164 - 10, 200 - 20, 200 - 20); break;
+ case 4: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 224 - 20, 255 - 30, 196 - 20); break;
+ case 5: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 205 - 20, 235 - 30, 196 - 20); break;
+ case 6: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 164 - 10, 164 - 10, 164 - 10); break;
+ case 7: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 225 - 30, 245 - 30, 205 - 20); break;
+ case 8: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 205 - 20, 255 - 30, 225 - 30); break;
+ case 9: drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 245 - 30, 245 - 30, 245 - 30); break;
}
}else{
- backbuffer.fillRect(line_rect, RGB(96, 96, 96));
+ drawfillrect(line_rect.x, line_rect.y, line_rect.width, line_rect.height, 96, 96, 96);
}
}
@@ -1999,184 +2206,229 @@
if (!obj.entities[i].invis && obj.entities[i].active) {
if (obj.entities[i].size == 0) { // Sprites
if (flipmode) {
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
setcol(obj.entities[i].colour, help);
- flipsprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ flipsprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
if (map.warpx) {
//screenwrapping!
if (tpoint.x < 0) {
- tpoint.x += 320;
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 320, int(obj.entities[i].yp));
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
}
if (tpoint.x > 300) {
- tpoint.x -= 320;
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) - 320, int(obj.entities[i].yp));
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
}
}else if (map.warpy) {
if (tpoint.y < 0) {
- tpoint.y += 230;
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) + 230);
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
}
if (tpoint.y > 210) {
- tpoint.y -= 230;
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) - 230);
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
}
}
- }else{
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
+ }else {
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
setcol(obj.entities[i].colour, help);
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
if (map.warpx) {
//screenwrapping!
if (tpoint.x < 0) {
- tpoint.x += 320;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 320, int(obj.entities[i].yp));
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
if (tpoint.x > 300) {
- tpoint.x -= 320;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) - 320, int(obj.entities[i].yp));
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
}else if (map.warpy) {
if (tpoint.y < 0) {
- tpoint.y += 230;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) + 230);
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
if (tpoint.y > 210) {
- tpoint.y -= 230;
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) - 230);
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
}
}
}else if (obj.entities[i].size == 1) { // Tiles
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
}else if (obj.entities[i].size == 2) { // Special: Moving platform, 4 tiles
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- if(map.custommode){
- backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- }else{
- backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ if (map.custommode) {
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 8, int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 16, int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition)
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 24, int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition)
+ }else {
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 8, int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 16, int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition)
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp) + 24, int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition)
}
}else if (obj.entities[i].size == 3) { // Big chunky pixels!
- prect.x = obj.entities[i].xp; prect.y = obj.entities[i].yp;
+ prect.x = int(obj.entities[i].xp); prect.y = int(obj.entities[i].yp);
//A seperate index of colours, for simplicity
- if(obj.entities[i].colour==1){
- backbuffer.fillRect(prect, RGB(196 - (Math.random() * 64), 10, 10));
+ if (obj.entities[i].colour == 1) {
+ drawfillrect(prect.x, prect.y, prect.width, prect.height, 196 - (Math.random() * 64), 10, 10);
}else if (obj.entities[i].colour == 2) {
- backbuffer.fillRect(prect, RGB(160- help.glow/2 - (Math.random()*20), 200- help.glow/2, 220 - help.glow));
+ drawfillrect(prect.x, prect.y, prect.width, prect.height, 160 - help.glow / 2 - (Math.random() * 20), 200 - help.glow / 2, 220 - help.glow);
}
}else if (obj.entities[i].size == 4) { // Small pickups
- drawhuetile(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].tile, obj.entities[i].colour);
+ drawhuetile(int(obj.entities[i].xp), int(obj.entities[i].yp), obj.entities[i].tile, obj.entities[i].colour);
}else if (obj.entities[i].size == 5) { //Horizontal Line
- line_rect.x = obj.entities[i].xp; line_rect.y = obj.entities[i].yp;
+ line_rect.x = int(obj.entities[i].xp); line_rect.y = int(obj.entities[i].yp);
line_rect.width = obj.entities[i].w; line_rect.height = 1;
drawgravityline(i, obj);
}else if (obj.entities[i].size == 6) { //Vertical Line
- line_rect.x = obj.entities[i].xp; line_rect.y = obj.entities[i].yp;
+ line_rect.x = int(obj.entities[i].xp); line_rect.y = int(obj.entities[i].yp);
line_rect.width = 1; line_rect.height = obj.entities[i].h;
drawgravityline(i, obj);
}else if (obj.entities[i].size == 7) { //Teleporter
- drawtele(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].drawframe, obj.entities[i].colour, help);
+ drawtele(int(obj.entities[i].xp), int(obj.entities[i].yp), obj.entities[i].drawframe, obj.entities[i].colour, help);
}else if (obj.entities[i].size == 8) { // Special: Moving platform, 8 tiles
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
if (map.custommode) {
- backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(entcolours[obj.entities[i].drawframe], tiles_rect, tpoint);
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 8), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 16), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 24), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 32), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 40), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 48), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 56), int(obj.entities[i].yp));
+ backbuffer.draw(entcolours[obj.entities[i].drawframe], tposition);
}else{
- backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
- tpoint.x += 8; backbuffer.copyPixels(tiles[obj.entities[i].drawframe], tiles_rect, tpoint);
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 8), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 16), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 24), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 32), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 40), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 48), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
+ tposition.identity(); tposition.translate(int(obj.entities[i].xp + 56), int(obj.entities[i].yp));
+ backbuffer.draw(tiles[obj.entities[i].drawframe], tposition);
}
}else if (obj.entities[i].size == 9) { // Really Big Sprite! (2x2)
if (flipmode) {
- setcol(obj.entities[i].colour, help);
+ setcol(obj.entities[i].colour, help);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- flipsprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ flipsprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp;
- flipsprites[obj.entities[i].drawframe+1].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe+1], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp));
+ flipsprites[obj.entities[i].drawframe + 1].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe + 1], tposition);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp+32;
- flipsprites[obj.entities[i].drawframe+12].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe+12], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) + 32);
+ flipsprites[obj.entities[i].drawframe + 12].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe + 12], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp+32;
- flipsprites[obj.entities[i].drawframe+13].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe + 13], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp) + 32);
+ flipsprites[obj.entities[i].drawframe + 13].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe + 13], tposition);
}else{
- setcol(obj.entities[i].colour, help);
+ setcol(obj.entities[i].colour, help);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp;
- sprites[obj.entities[i].drawframe+1].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe+1], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp));
+ sprites[obj.entities[i].drawframe + 1].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe + 1], tposition);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp+32;
- sprites[obj.entities[i].drawframe+12].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe+12], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp) + 32);
+ sprites[obj.entities[i].drawframe + 12].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe + 12], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp+32;
- sprites[obj.entities[i].drawframe+13].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe + 13], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp) + 32);
+ sprites[obj.entities[i].drawframe + 13].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe + 13], tposition);
}
}else if (obj.entities[i].size == 10) { // 2x1 Sprite
if (flipmode) {
- setcol(obj.entities[i].colour, help);
+ setcol(obj.entities[i].colour, help);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- flipsprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ flipsprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp;
- flipsprites[obj.entities[i].drawframe+1].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe + 1], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp));
+ flipsprites[obj.entities[i].drawframe + 1].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe + 1], tposition);
}else{
- setcol(obj.entities[i].colour, help);
+ setcol(obj.entities[i].colour, help);
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
- tpoint.x = obj.entities[i].xp+32; tpoint.y = obj.entities[i].yp;
- sprites[obj.entities[i].drawframe+1].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe + 1], sprites_rect, tpoint);
+ tposition.identity();
+ tposition.translate(int(obj.entities[i].xp) + 32, int(obj.entities[i].yp));
+ sprites[obj.entities[i].drawframe + 1].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe + 1], tposition);
}
}else if (obj.entities[i].size == 11) { //The fucking elephant
- setcol(obj.entities[i].colour, help);
- images[3].colorTransform(images[3].rect, ct);
- drawimage(3, obj.entities[i].xp, obj.entities[i].yp);
+ setcol(obj.entities[i].colour, help);
+ images[3].color = ct.color;
+ drawimage(3, int(obj.entities[i].xp), int(obj.entities[i].yp));
}else if (obj.entities[i].size == 12) { // Regular sprites that don't wrap
if (flipmode) {
//forget this for a minute;
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
+ tpoint.x = int(obj.entities[i].xp); tpoint.y = int(obj.entities[i].yp);
setcol(obj.entities[i].colour, help);
- flipsprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ flipsprites[obj.entities[i].drawframe].color = ct.color;
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
//if we're outside the screen, we need to draw indicators
if (obj.entities[i].xp < -20 && obj.entities[i].vx > 0) {
@@ -2188,8 +2440,11 @@
tpoint.y = tpoint.y+4;
setcol(23, help);
- tiles[1167].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[1167], tiles_rect, tpoint);
+ tiles[1167].color = ct.color;
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+
+ backbuffer.draw(tiles[1167], tposition);
}else if (obj.entities[i].xp > 340 && obj.entities[i].vx < 0) {
if (obj.entities[i].xp > 420) {
tpoint.x = 320 - (int(( obj.entities[i].xp-320) / 10));
@@ -2199,14 +2454,20 @@
tpoint.y = tpoint.y+4;
setcol(23, help);
- tiles[1166].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[1166], tiles_rect, tpoint);
+ tiles[1166].color = ct.color;
+
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+
+ backbuffer.draw(tiles[1166], tposition);
}
}else{
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
+ tpoint.x = int(obj.entities[i].xp); tpoint.y = int(obj.entities[i].yp);
setcol(obj.entities[i].colour, help);
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- backbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, tpoint);
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
//if we're outside the screen, we need to draw indicators
@@ -2219,8 +2480,11 @@
tpoint.y = tpoint.y+4;
setcol(23, help);
- tiles[1167].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[1167], tiles_rect, tpoint);
+ tiles[1167].color = ct.color;
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+
+ backbuffer.draw(tiles[1167], tposition);
}else if (obj.entities[i].xp > 340 && obj.entities[i].vx < 0) {
if (obj.entities[i].xp > 420) {
tpoint.x = 320 - (int(( obj.entities[i].xp-320) / 10));
@@ -2230,37 +2494,31 @@
tpoint.y = tpoint.y+4;
setcol(23, help);
- tiles[1166].colorTransform(tiles_rect, ct);
- backbuffer.copyPixels(tiles[1166], tiles_rect, tpoint);
+ tiles[1166].color = ct.color;
+
+ tposition.identity();
+ tposition.translate(tpoint.x, tpoint.y);
+
+ backbuffer.draw(tiles[1166], tposition);
}
}
}else if (obj.entities[i].size == 13) { // Special for epilogue: huge hero!
if (flipmode) {
- scaleMatrix = new Matrix();
- scaleMatrix.scale(6, 6);
- bigbuffer.fillRect(bigbuffer.rect, 0x000000);
+ tposition.identity();
+ tposition.scale(6, 6);
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
setcol(obj.entities[i].colour, help);
- flipsprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- bigbuffer.copyPixels(flipsprites[obj.entities[i].drawframe], sprites_rect, new Point(0, 0));
-
- scaleMatrix.translate(obj.entities[i].xp, obj.entities[i].yp);
- backbuffer.draw(bigbufferscreen, scaleMatrix);
- scaleMatrix.translate(-obj.entities[i].xp, -obj.entities[i].yp);
+ flipsprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(flipsprites[obj.entities[i].drawframe], tposition);
}else {
- scaleMatrix = new Matrix();
- scaleMatrix.scale(6, 6);
- bigbuffer.fillRect(bigbuffer.rect, 0x000000);
+ tposition.identity();
+ tposition.scale(6, 6);
+ tposition.translate(int(obj.entities[i].xp), int(obj.entities[i].yp));
- tpoint.x = obj.entities[i].xp; tpoint.y = obj.entities[i].yp;
setcol(obj.entities[i].colour, help);
- sprites[obj.entities[i].drawframe].colorTransform(sprites_rect, ct);
- bigbuffer.copyPixels(sprites[obj.entities[i].drawframe], sprites_rect, new Point(0, 0));
-
- scaleMatrix.translate(obj.entities[i].xp, obj.entities[i].yp);
- backbuffer.draw(bigbufferscreen, scaleMatrix);
- scaleMatrix.translate(-obj.entities[i].xp, -obj.entities[i].yp);
+ sprites[obj.entities[i].drawframe].color = ct.color;
+ backbuffer.draw(sprites[obj.entities[i].drawframe], tposition);
}
}
}
@@ -2268,67 +2526,81 @@
}
public function drawbuffertile(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- buffer.copyPixels(tiles[t], tiles_rect, tpoint);
+ trace("dwgfx.drawbuffertile() is not implemented yet");
}
public function drawforetile(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- frontbuffer.copyPixels(tiles[t], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ frontbuffer_meshbatch.addMesh(tiles[t], tposition);
}
public function drawforetile2(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- frontbuffer.copyPixels(tiles2[t], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ frontbuffer_meshbatch.addMesh(tiles2[t], tposition);
}
public function drawforetile3(x:int, y:int, t:int, off:int):void {
- tpoint.x = x; tpoint.y = y;
- frontbuffer.copyPixels(tiles3[t+(off*30)], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ frontbuffer_meshbatch.addMesh(tiles3[t+(off*30)], tposition);
}
-
public function drawtele(x:int, y:int, t:int, c:int, help:helpclass):void {
- tpoint.x = x; tpoint.y = y;
+ tele[0].color = RGB(16, 16, 16);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tele[0], tposition);
- setcolreal(RGB(16,16,16));
- tele[0].colorTransform(tele_rect, ct);
- backbuffer.copyPixels(tele[0], tele_rect, tpoint);
-
- setcol(c, help);
+ setcol(c, help);
if (t > 9) t = 8; if (t < 0) t = 0;
- tele[t].colorTransform(tele_rect, ct);
- backbuffer.copyPixels(tele[t], tele_rect, tpoint);
+ tele[t].color = ct.color;
+
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tele[t], tposition);
}
public function drawtile(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- backbuffer.copyPixels(tiles[t], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tiles[t], tposition);
}
public function drawtile2(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- backbuffer.copyPixels(tiles2[t], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tiles2[t], tposition);
}
public function drawtile3(x:int, y:int, t:int, off:int):void {
- tpoint.x = x; tpoint.y = y;
- backbuffer.copyPixels(tiles3[t+(off*30)], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tiles3[t + (off * 30)], tposition);
+ }
+
+ public function drawtile3_batch(x:int, y:int, t:int, off:int):void {
+ tposition.identity();
+ tposition.translate(x, y);
+ towerbufferforeground_meshbatch.addMesh(tiles3[t + (off * 30)], tposition);
}
public function drawtowertile3(x:int, y:int, t:int, off:int):void {
- tpoint.x = x; tpoint.y = y;
- towerbuffer.copyPixels(tiles3[t+(off*30)], tiles_rect, tpoint);
+ tposition.identity();
+ tposition.translate(x, y);
+ towerbufferbackground_meshbatch.addMesh(tiles3[t+(off*30)], tposition);
}
public function drawtowertile(x:int, y:int, t:int):void {
- tpoint.x = x; tpoint.y = y;
- towerbuffer.copyPixels(tiles2[t], tiles_rect, tpoint, null, null, true);
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(tiles2[t], tposition);
}
public function drawmap(map:mapclass):void {
if (!foregrounddrawn) {
- frontbuffer.fillRect(frontbuffer.rect, 0x000000);
+ frontbuffer_meshbatch.clear();
if(map.tileset==0){
for (j = 0; j < 29+map.extrarow; j++) {
for (i = 0; i < 40; i++) {
@@ -2348,17 +2620,17 @@
}
}
}
- foregrounddrawn=true;
+ foregrounddrawn = true;
}
- backbuffer.copyPixels(frontbuffer, frontbuffer.rect, tl);
+ backbuffer.draw(frontbuffer_meshbatch);
}
public function drawfinalmap(map:mapclass):void {
//Update colour cycling for final level
if (map.final_colormode) {
map.final_aniframedelay--;
- if(map.final_aniframedelay==0) foregrounddrawn=false;
+ if (map.final_aniframedelay == 0) foregrounddrawn = false;
if (map.final_aniframedelay <= 0) {
map.final_aniframedelay = 2;
map.final_aniframe++;
@@ -2367,9 +2639,9 @@
}
if (!foregrounddrawn) {
- frontbuffer.fillRect(frontbuffer.rect, 0x000000);
+ frontbuffer_meshbatch.clear();
if(map.tileset==0){
- for (j = 0; j < 29+map.extrarow; j++) {
+ for (j = 0; j < 29 + map.extrarow; j++) {
for (i = 0; i < 40; i++) {
if(map.contents[i + map.vmult[j]]>0) drawforetile(i * 8, j * 8, map.finalat(i,j));
}
@@ -2384,54 +2656,69 @@
foregrounddrawn=true;
}
- backbuffer.copyPixels(frontbuffer, frontbuffer.rect, tl);
+ backbuffer.draw(frontbuffer_meshbatch);
}
public function drawmaptileat(xp:int, yp:int, mapx:int, mapy:int, map:mapclass):void {
- if (mapx < 100) mapx = 119; if (mapy < 100) mapy = 119;
- if (mapx > 119) mapx = 100; if (mapy > 119) mapy = 100;
- if (map.explored[(mapx - 100) + ((mapy - 100) * 20)] == 1) {
- madrect.x = (mapx - 100)*12; madrect.y = (mapy - 100)*9; madrect.width = 12; madrect.height = 9;
- madpoint.x = xp; madpoint.y = yp;
- backbuffer.copyPixels(images[1], madrect, madpoint);
- }else {
- drawimage(2, xp, yp);
- }
+ //Not used anymore, phew
+ trace("dwgfx.drawmaptileat() is not implemented yet");
}
public function drawminimap(game:gameclass, map:mapclass):void {
- drawfillrect(272, 8, 40, 31, 196, 196, 196);
- drawfillrect(273, 9, 38, 29, 164,164,164);
- for (j = 0; j < 3; j++){
- for (i = 0; i < 3; i++) {
- drawmaptileat(274 + (i * 12), 10 + (j * 9), game.roomx - 1 + i, game.roomy - 1 + j, map);
- }
- }
- }
-
- public function drawrect(x:int, y:int, w:int, h:int, r:int, g:int, b:int):void {
- //Draw the retangle indicated by that object
- madrect.x = x; madrect.y = y;
- madrect.width = w; madrect.height = 1;
- backbuffer.fillRect(madrect, RGB(r,g,b));
-
- madrect.width = 1; madrect.height = h;
- backbuffer.fillRect(madrect, RGB(r,g,b));
-
- madrect.x = x + w - 1;
- madrect.width = 1; madrect.height = h;
- backbuffer.fillRect(madrect, RGB(r,g,b));
-
- madrect.x = x; madrect.y = y + h - 1;
- madrect.width = w; madrect.height = 1;
- backbuffer.fillRect(madrect, RGB(r,g,b));
+ //Not used anymore, phew
+ trace("dwgfx.drawminimap() is not implemented yet");
}
- public function drawfillrect(x:int, y:int, w:int, h:int, r:int, g:int, b:int):void {
+ public function drawrect(x:int, y:int, w:int, h:int, r:int, g:int, b:int):void {
//Draw the retangle indicated by that object
- madrect.x = x; madrect.y = y;
- madrect.width = w; madrect.height = h;
- backbuffer.fillRect(madrect, RGB(r,g,b));
+ tquad.x = x; tquad.y = y;
+ tquad.width = w; tquad.height = 1;
+ tquad.color = RGB(r, g, b);
+ backbuffer.draw(tquad);
+
+ tquad.width = 1; tquad.height = h;
+ backbuffer.draw(tquad);
+
+ tquad.x = x + w - 1;
+ backbuffer.draw(tquad);
+
+ tquad.x = x; tquad.y = y + h - 1;
+ tquad.width = w; tquad.height = 1;
+ backbuffer.draw(tquad);
+ }
+
+ public function cls(c:int):void {
+ drawfillrect(0, 0, screenwidth, screenheight, c);
+ }
+
+ public function drawfillrect(x:int, y:int, w:int, h:int, r:int, g:int = -1, b:int = -1):void {
+ //Draw the retangle indicated by that object
+ tquad.x = x;
+ tquad.y = y;
+ tquad.width = w;
+ tquad.height = h;
+ if (b == -1) {
+ tquad.color = r;
+ }else{
+ tquad.color = RGB(r, g, b);
+ }
+
+ backbuffer.draw(tquad);
+ }
+
+ public function drawfillrect_onimage(img:RenderTexture, x:int, y:int, w:int, h:int, r:int, g:int = -1, b:int = -1):void {
+ //Draw the retangle indicated by that object
+ tquad.x = x;
+ tquad.y = y;
+ tquad.width = w;
+ tquad.height = h;
+ if (b == -1) {
+ tquad.color = r;
+ }else{
+ tquad.color = RGB(r, g, b);
+ }
+
+ img.draw(tquad);
}
public function printcrewname(x:int, y:int, t:int):void {
@@ -2470,82 +2757,85 @@
}
}
- public function printmask(x:int, y:int, t:String, cen:Boolean = false):void {
- if (cen) x = 160 - (len(t) / 2);
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos-1; tpoint.y = y;
- if (flipmode) {
- backbuffer.copyPixels(flipbfontmask[cur], bfont_rect, tpoint);
- }else{
- backbuffer.copyPixels(bfontmask[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
- }
+ public function printmask(x:int, y:int, t:String, cen:Boolean = false):void {
+ trace("dwgfx.printmask() is not implemented yet");
+ }
+
+ public function textbox_print(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
+ trace("dwgfx.textbox_print() is not implemented yet");
}
public function print(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if (cen) x = 160 - (len(t) / 2);
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos; tpoint.y = y;
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(flipbfont[cur], bfont_rect, tpoint);
- }else {
- bfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(bfont[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
+ if (cen) {
+ x = 0;
+ ttf.format.horizontalAlign = "center";
+ }else {
+ ttf.format.horizontalAlign = "left";
+ }
+
+ ttf.format.color = RGB(r, g, b);
+ ttf.text = t;
+
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(x, y + 8);
+ backbuffer.draw(ttf, tposition);
+ }else{
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(ttf, tposition);
}
}
public function rprint(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if (cen) x = 308 - (len(t));
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos; tpoint.y = y;
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(flipbfont[cur], bfont_rect, tpoint);
- }else{
- bfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(bfont[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
+ ttf.format.horizontalAlign = "right";
+ x = x - 320;
+
+ ttf.format.color = RGB(r, g, b);
+ ttf.text = t;
+
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(x, y + 8);
+ backbuffer.draw(ttf, tposition);
+ }else {
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(ttf, tposition);
}
}
public function printoff(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
- if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
+ if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if (cen) x = (160 - (len(t) / 2))+x;
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos; tpoint.y = y;
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(flipbfont[cur], bfont_rect, tpoint);
- }else{
- bfont[cur].colorTransform(bfont_rect, ct);
- backbuffer.copyPixels(bfont[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
+ if (cen) {
+ ttf.format.horizontalAlign = "center";
+ }else {
+ ttf.format.horizontalAlign = "left";
+ }
+
+ ttf.format.color = RGB(r, g, b);
+ ttf.text = t;
+
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(x, y + 8);
+ backbuffer.draw(ttf, tposition);
+ }else {
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(ttf, tposition);
}
}
- public function bprint(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean=false):void {
+ public function bprint(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
//printmask(x, y, t, cen);
print(x, y - 1, t, 0, 0, 0, cen);
if (cen) {
@@ -2561,38 +2851,11 @@
}
public function printmasktemptile(x:int, y:int, t:String, cen:Boolean = false):void {
- if (cen) x = 160- (len(t) / 2);
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos - 1; tpoint.y = y;
- if (flipmode) {
- temptile.copyPixels(flipbfontmask[cur], bfont_rect, tpoint);
- }else{
- temptile.copyPixels(bfontmask[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
- }
+ trace("dwgfx.printmasktemptile() is not implemented yet");
}
public function printtemptile(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false):void {
- if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
- if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if (cen) x = 160 - (len(t) / 2);
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- tpoint.x = x + bfontpos; tpoint.y = y;
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- temptile.copyPixels(flipbfont[cur], bfont_rect, tpoint);
- }else{
- bfont[cur].colorTransform(bfont_rect, ct);
- temptile.copyPixels(bfont[cur], bfont_rect, tpoint);
- }
- bfontpos+=bfontlen[cur];
- }
+ trace("dwgfx.printtemptile() is not implemented yet");
}
public function onscreen(t:int):Boolean {
@@ -2603,175 +2866,154 @@
public function bigrprint(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false, sc:Number = 2):void {
if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
+ ttf.format.horizontalAlign = "right";
+ x = x - 320;
- scaleMatrix = new Matrix();
- scaleMatrix.scale(sc, sc);
+ ttf.format.color = RGB(r, g, b);
+ ttf.format.size = BitmapFont.NATIVE_SIZE * sc;
+ ttf.text = t;
- bigbuffer.fillRect(bigbuffer.rect, 0x000000);
-
- x = x / sc;
-
- x -= (len(t));
-
- //if (r < -1) r = -1; if (g < 0) g = 0; if (b < 0) b = 0;?
- //if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if(sc==2){
- if (cen) x = 80 - (len(t)/2);
- }else if (sc == 3) {
- if (cen) x = 160/3 - (len(t) / 2);
- }else if (sc == 4) {
- if (cen) x = 40 - (len(t) / 2);
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(x, y + (8 * sc));
+ backbuffer.draw(ttf, tposition);
+ }else {
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(ttf, tposition);
}
- bfontpos = 0;
- for (i = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- bigbuffer.copyPixels(flipbfont[cur], bfont_rect, new Point(x + bfontpos, 0));
- }else {
- bfont[cur].colorTransform(bfont_rect, ct);
- bigbuffer.copyPixels(bfont[cur], bfont_rect, new Point(x + bfontpos, 0));
- }
- bfontpos+=bfontlen[cur];
- }
-
- scaleMatrix.translate(0, y);
- backbuffer.draw(bigbufferscreen, scaleMatrix);
- scaleMatrix.translate(0, -y);
+ ttf.format.size = BitmapFont.NATIVE_SIZE;
}
public function bigprint(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean = false, sc:Number = 2):void {
- if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
+ if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
-
- scaleMatrix = new Matrix();
- scaleMatrix.scale(sc, sc);
-
- bigbuffer.fillRect(bigbuffer.rect, 0x000000);
-
- x = x / sc;
-
- //if (r < -1) r = -1; if (g < 0) g = 0; if (b < 0) b = 0;?
- //if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
- ct.color = RGB(r, g, b);
- if(sc==2){
- if (cen) x = 80 - (len(t)/2);
- }else if (sc == 3) {
- if (cen) x = 160/3 - (len(t) / 2);
- }else if (sc == 4) {
- if (cen) x = 40 - (len(t) / 2);
- }
- bfontpos = 0;
- for (var ti:int = 0; ti < t.length; ti++) {
- cur = t.charCodeAt(ti);
- if (flipmode) {
- flipbfont[cur].colorTransform(bfont_rect, ct);
- bigbuffer.copyPixels(flipbfont[cur], bfont_rect, new Point(x + bfontpos, 0));
- }else {
- bfont[cur].colorTransform(bfont_rect, ct);
- bigbuffer.copyPixels(bfont[cur], bfont_rect, new Point(x + bfontpos, 0));
- }
- bfontpos+=bfontlen[cur];
+ if (cen) {
+ x = 0;
+ ttf.format.horizontalAlign = "center";
+ }else {
+ ttf.format.horizontalAlign = "left";
}
- scaleMatrix.translate(0, y);
- backbuffer.draw(bigbufferscreen, scaleMatrix);
- scaleMatrix.translate(0, -y);
+ ttf.format.color = RGB(r, g, b);
+ ttf.format.size = BitmapFont.NATIVE_SIZE * sc;
+ ttf.text = t;
+
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(x, y + (8 * sc));
+ backbuffer.draw(ttf, tposition);
+ }else {
+ tposition.identity();
+ tposition.translate(x, y);
+ backbuffer.draw(ttf, tposition);
+ }
+
+ ttf.format.size = BitmapFont.NATIVE_SIZE;
}
- public function bprinttemptile(x:int, y:int, t:String, r:int, g:int, b:int, cen:Boolean=false):void {
- printmasktemptile(x, y, t, cen);
- printtemptile(x, y, t, r, g, b, cen);
- }
public function len(t:String):int {
- bfontpos = 0;
- for (var i:int = 0; i < t.length; i++) {
- cur = t.charCodeAt(i);
- bfontpos+=bfontlen[cur];
- }
- return bfontpos;
+ //For VVVVVV, we're using a fixed width font, so...
+ return t.length * 8;
}
public function flashlight():void {
- backbuffer.fillRect(backbuffer.rect, 0xBBBBBB);
+ drawfillrect(0, 0, 320, 240, 187, 187, 187);
}
public function screenshake():void {
- screenbuffer.lock();
- if(flipmode){
- tpoint.x = int((Math.random() * 7) - 4); tpoint.y = int((Math.random() * 7) - 4);
- flipmatrix.translate(tpoint.x, tpoint.y);
- screenbuffer.draw(backbuffer, flipmatrix);
- flipmatrix.translate(-tpoint.x, -tpoint.y);
- }else{
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tl, null, null, false);
- tpoint.x = (Math.random() * 7) - 4; tpoint.y = (Math.random() * 7) - 4;
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tpoint, null, null, false);
- }
- screenbuffer.unlock();
+ screenmenubuffer.draw(smallscreen);
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(int((Math.random() * 7) - 4), screenheight + int((Math.random() * 7) - 4));
+ drawfillrect(0, 0, screenwidth, screenheight, 0, 0, 0);
+ backbuffer.draw(screenmenubuffer_image, tposition);
+ }else{
+ tposition.identity();
+ tposition.translate(int((Math.random() * 7) - 4), int((Math.random() * 7) - 4));
+
+ backbuffer.draw(screenmenubuffer_image, tposition);
+ }
}
public function render():void {
- screenbuffer.lock();
- if(flipmode){
- screenbuffer.draw(backbuffer, flipmatrix);
- }else{
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tl, null, null, false);
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(0, screenheight);
+
+ screenmenubuffer.drawBundled(function():void {
+ screenmenubuffer.draw(smallscreen);
+ });
+
+ backbuffer.draw(screenmenubuffer_image, tposition);
}
- screenbuffer.unlock();
+ }
+
+ public function clear_menubuffer():void {
+ tquad.x = 0; tquad.y = 0;
+ tquad.width = screenwidth;
+ tquad.height = screenheight;
+ tquad.color = RGB(0, 0, 0);
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
+ menubuffer.drawBundled(function():void {
+ menubuffer.draw(tquad);
+ });
+ screenmenubuffer.drawBundled(function():void {
+ screenmenubuffer.draw(tquad);
+ });
+ }
+
+ public function setup_menubuffer():void {
+ menubuffer.draw(smallscreen);
}
public function menuoffrender():void {
- screenbuffer.lock();
- screenbuffer.copyPixels(menubuffer, menubuffer.rect, tl, null, null, false);
+ //The backbuffer currently contains the menu, so we save this...
+ screenmenubuffer.draw(smallscreen);
- if(flipmode){
- flipmatrix.translate(0, menuoffset);
- screenbuffer.draw(backbuffer, flipmatrix);
- flipmatrix.translate(0, -menuoffset);
+ //Then we draw the old in-game screen instead
+ backbuffer.draw(menubuffer_image);
+
+ //Finally, we draw the menu back on top of this, offset.
+ if (flipmode) {
+ tposition.identity();
+ tposition.scale(1, -1);
+ tposition.translate(0, screenheight + menuoffset);
+ backbuffer.draw(screenmenubuffer_image, tposition);
}else {
- tpoint.x = 0;
- tpoint.y = menuoffset;
- screenbuffer.copyPixels(backbuffer, backbuffer.rect, tpoint, null, null, false);
+ tposition.identity();
+ tposition.translate(0, menuoffset);
+ backbuffer.draw(screenmenubuffer_image, tposition);
}
-
- screenbuffer.unlock();
-
- backbuffer.lock();
- backbuffer.fillRect(backbuffer.rect, 0x000000);
- backbuffer.unlock();
}
- public var backgrounds:Vector. = new Vector.;
- public var images:Vector. = new Vector.;
- public var playerlevelimages:Vector. = new Vector.;
- public var mobileimages:Vector. = new Vector.;
- public var tele:Vector. = new Vector.;
- public var tele_rect:Rectangle;
- public var tiles:Vector. = new Vector.;
- public var tiles2:Vector. = new Vector.;
- public var tiles3:Vector. = new Vector.;
- public var sprites:Vector. = new Vector.;
- public var flipsprites:Vector. = new Vector.;
- public var entcolours:Vector. = new Vector.;
- public var bfont:Vector. = new Vector.;
- public var bfontmask:Vector. = new Vector.;
- public var flipbfont:Vector. = new Vector.;
- public var flipbfontmask:Vector. = new Vector.;
- public var bfontlen:Vector. = new Vector.;
- public var bfontpos:int;
+ public var tquad:Quad;
+ public var ttf:TextField;
+ public var tposition:Matrix;
+ public var starlingassets:AssetManager;
+ public var starstage:Stage
+
+ public var backgrounds:Vector. = new Vector.;
+ public var images:Vector. = new Vector.;
+ public var playerlevelimages:Vector. = new Vector.;
+ public var mobileimages:Vector. = new Vector.;
+ public var tele:Vector. = new Vector.;
+ public var tiles:Vector. = new Vector.;
+ public var tiles2:Vector. = new Vector.;
+ public var tiles3:Vector. = new Vector.;
+ public var sprites:Vector. = new Vector.;
+ public var flipsprites:Vector. = new Vector.;
+ public var sprites_bitmap:Vector. = new Vector.;
+ public var flipsprites_bitmap:Vector. = new Vector.;
+ public var entcolours:Vector. = new Vector.;
+ public var customminimap:RenderTexture;
+
public var cur:int;
public var ct:ColorTransform;
public var tiles_rect:Rectangle;
@@ -2789,22 +3031,30 @@
public var tempstring:String;
public var alphamult:uint;
public var stemp:String;
- public var buffer:BitmapData;
public var i:int, j:int, k:int, m:int;
public var tpoint:Point, trect:Rectangle;
public var madrect:Rectangle, madpoint:Point;
- public var temptile:BitmapData;
- public var tempsprite:BitmapData;
+ public var temptile:RenderTexture;
+ public var tempsprite:RenderTexture;
public var footerrect:Rectangle;
+
//Actual backgrounds
- public var backbuffer:BitmapData;
- public var frontbuffer:BitmapData;
- public var towerbuffer:BitmapData;
- public var screenbuffer:BitmapData;
- public var menubuffer:BitmapData;
- public var screen:Bitmap;
+ public var backbuffer:RenderTexture;
+ public var frontbuffer_meshbatch:MeshBatch;
+ public var menubuffer:RenderTexture;
+ public var menubuffer_image:Image;
+ public var screenmenubuffer:RenderTexture;
+ public var screenmenubuffer_image:Image;
+ public var towerbufferforeground_meshbatch:MeshBatch;
+ public var towerbufferbackground_meshbatch:MeshBatch;
+ public var towerbufferstatic_meshbatch:MeshBatch;
+ public var warpzonehorizontal_meshbatch:MeshBatch;
+ public var warpzonevertical_meshbatch:MeshBatch;
+ public var screen:Image;
+ public var smallscreen:Image;
public var updatebackground:Boolean;
+
//Textbox Stuff
public var ntextbox:int;
public var textbox:Vector. = new Vector.;
@@ -2846,17 +3096,16 @@
public var flipfontmatrix:Matrix = new Matrix();
public var flipfontmatrix2:Matrix = new Matrix();
- public var scaleMatrix:Matrix = new Matrix();
- public var bigbuffer:BitmapData;
- public var bigbufferscreen:Bitmap;
-
//Mobile stuff
public var screensizemultiplier:Number;
public var screenoffx:int, screenoffy:int;
- public var buttonimg:Vector. = new Vector.;
- public var buttonscreen:Vector. = new Vector.;
+ public var buttonsready:Boolean = false;
+ public var button_texture:Vector. = new Vector.;
+ public var button_image:Vector. = new Vector.;
+ public var button_image_width:Vector. = new Vector.;
+ public var button_image_height:Vector. = new Vector.;
public var buttonactive:Vector. = new Vector.;
public var buttonhighlight:Vector. = new Vector.;
@@ -2870,5 +3119,11 @@
public var b_gap:int = 40, b_size:int = 26;
public var devicex:int, devicey:int;
+
+ [Embed(source = "../data/bitmapsprites.png")]
+ public static const img_bitmapsprites:Class;
+
+ [Embed(source = "../data/bitmapflipsprites.png")]
+ public static const img_bitmapflipsprites:Class;
}
}
\ No newline at end of file
diff --git a/mobile_version/src/edentitiesclass.as b/mobile_version/src/edentitiesclass.as
index 493eaf33..78d4ddd0 100644
--- a/mobile_version/src/edentitiesclass.as
+++ b/mobile_version/src/edentitiesclass.as
@@ -1,9 +1,4 @@
package {
- import flash.display.*;
- import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
-
public class edentitiesclass {
public function edentitiesclass():void {
clear();
diff --git a/mobile_version/src/editor.as b/mobile_version/src/editor.as
index 6dbe5828..8edb57ea 100644
--- a/mobile_version/src/editor.as
+++ b/mobile_version/src/editor.as
@@ -1,9 +1,9 @@
package {
- import flash.display.*;
- import flash.display3D.textures.RectangleTexture;
import flash.geom.*;
import flash.events.*;
import flash.net.*;
+ import starling.display.Image;
+ import starling.textures.RenderTexture;
public class editor {
public static function init():void {
@@ -1249,17 +1249,17 @@ package {
}
public static function fillbox(dwgfx:dwgraphicsclass, x:int, y:int, x2:int, y2:int, c:int):void {
- dwgfx.backbuffer.fillRect(new Rectangle(x, y, x2 - x, 1), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x, y2 - 1, x2 - x, 1), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x, y, 1, y2 - y), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x2 - 1, y, 1, y2 - y), c);
+ dwgfx.drawfillrect(x, y, x2 - x, 1, c);
+ dwgfx.drawfillrect(x, y2 - 1, x2 - x, 1, c);
+ dwgfx.drawfillrect(x, y, 1, y2 - y, c);
+ dwgfx.drawfillrect(x2 - 1, y, 1, y2 - y, c);
}
public static function fillboxabs(dwgfx:dwgraphicsclass, x:int, y:int, x2:int, y2:int, c:int):void {
- dwgfx.backbuffer.fillRect(new Rectangle(x, y, x2, 1), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x, y + y2 - 1, x2, 1), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x, y, 1, y2), c);
- dwgfx.backbuffer.fillRect(new Rectangle(x + x2 - 1, y, 1, y2), c);
+ dwgfx.drawfillrect(x, y, x2, 1, c);
+ dwgfx.drawfillrect(x, y + y2 - 1, x2, 1, c);
+ dwgfx.drawfillrect(x, y, 1, y2, c);
+ dwgfx.drawfillrect(x + x2 - 1, y, 1, y2, c);
}
public static function generatecustomminimap(dwgfx:dwgraphicsclass, map:mapclass):void {
@@ -1291,68 +1291,74 @@ package {
map.custommmysize = 180 - (map.custommmyoff * 2);
}
- dwgfx.images[12].fillRect(dwgfx.images[12].rect, dwgfx.RGBA(0, 0, 0));
-
- var tm:int = 0;
- var temp:int = 0;
- //Scan over the map size
- if(mapheight<=5 && mapwidth<=5){
- //4x map
- for (var j2:int = 0; j2 < mapheight; j2++){
- for (var i2:int = 0; i2 < mapwidth; i2++) {
- //Ok, now scan over each square
- tm = 196;
- if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
-
- for (var j:int = 0; j < 36; j++) {
- for (var i:int = 0; i < 48; i++) {
- temp = absfree(int(i * 0.83) + (i2 * 40), int(j * 0.83) + (j2 * 30));
- if(temp>=1){
- //Fill in this pixel
- dwgfx.images[12].fillRect(new Rectangle((i2 * 48) + i, (j2 * 36) + j, 1, 1), dwgfx.RGBA(tm, tm, tm));
- }
- }
- }
- }
- }
- }else if (mapheight <= 10 && mapwidth <= 10) {
- //2x map
- for (j2 = 0; j2 < mapheight; j2++) {
- for (i2 = 0; i2 < mapwidth; i2++) {
- //Ok, now scan over each square
- tm = 196;
- if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
-
- for (j = 0; j < 18; j++) {
- for (i = 0; i < 24; i++) {
- temp = absfree(int(i * 1.6) + (i2 * 40), int(j * 1.6) + (j2 * 30));
- if (temp >= 1) {
- //Fill in this pixel
- dwgfx.images[12].fillRect(new Rectangle((i2 * 24) + i, (j2 * 18) + j, 1, 1), dwgfx.RGBA(tm, tm, tm));
- }
- }
- }
- }
- }
- }else {
- for (j2 = 0; j2 < mapheight; j2++) {
- for (i2 = 0; i2 < mapwidth; i2++) {
- //Ok, now scan over each square
- tm=196;
- if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
-
- for (j = 0; j < 9; j++) {
- for (i = 0; i < 12; i++) {
- temp = absfree(3 + (i * 3) + (i2 * 40), (j * 3) + (j2 * 30));
- if(temp>=1){
- //Fill in this pixel
- dwgfx.images[12].fillRect(new Rectangle((i2 * 12) + i, (j2 * 9) + j, 1, 1), dwgfx.RGBA(tm, tm, tm));
- }
- }
- }
- }
- }
+ if (dwgfx.customminimap == null) {
+ dwgfx.customminimap = new RenderTexture(240, 180);
+ dwgfx.images[12] = new Image(dwgfx.customminimap);
}
+ dwgfx.customminimap.clear(dwgfx.RGB(0, 0, 0), 1.0);
+
+ dwgfx.customminimap.drawBundled(function():void {
+ var tm:int = 0;
+ var temp:int = 0;
+ //Scan over the map size
+ if(mapheight<=5 && mapwidth<=5){
+ //4x map
+ for (var j2:int = 0; j2 < mapheight; j2++){
+ for (var i2:int = 0; i2 < mapwidth; i2++) {
+ //Ok, now scan over each square
+ tm = 196;
+ if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
+
+ for (var j:int = 0; j < 36; j++) {
+ for (var i:int = 0; i < 48; i++) {
+ temp = absfree(int(i * 0.83) + (i2 * 40), int(j * 0.83) + (j2 * 30));
+ if(temp>=1){
+ //Fill in this pixel
+ dwgfx.drawfillrect_onimage(dwgfx.customminimap, (i2 * 48) + i, (j2 * 36) + j, 1, 1, tm, tm, tm);
+ }
+ }
+ }
+ }
+ }
+ }else if (mapheight <= 10 && mapwidth <= 10) {
+ //2x map
+ for (j2 = 0; j2 < mapheight; j2++) {
+ for (i2 = 0; i2 < mapwidth; i2++) {
+ //Ok, now scan over each square
+ tm = 196;
+ if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
+
+ for (j = 0; j < 18; j++) {
+ for (i = 0; i < 24; i++) {
+ temp = absfree(int(i * 1.6) + (i2 * 40), int(j * 1.6) + (j2 * 30));
+ if (temp >= 1) {
+ //Fill in this pixel
+ dwgfx.drawfillrect_onimage(dwgfx.customminimap, (i2 * 24) + i, (j2 * 18) + j, 1, 1, tm, tm, tm);
+ }
+ }
+ }
+ }
+ }
+ }else {
+ for (j2 = 0; j2 < mapheight; j2++) {
+ for (i2 = 0; i2 < mapwidth; i2++) {
+ //Ok, now scan over each square
+ tm=196;
+ if (level[i2 + (j2 * maxwidth)].tileset == 1) tm = 96;
+
+ for (j = 0; j < 9; j++) {
+ for (i = 0; i < 12; i++) {
+ temp = absfree(3 + (i * 3) + (i2 * 40), (j * 3) + (j2 * 30));
+ if(temp>=1){
+ //Fill in this pixel
+ dwgfx.drawfillrect_onimage(dwgfx.customminimap, (i2 * 12) + i, (j2 * 9) + j, 1, 1, tm, tm, tm);
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
public static function editorrender(dwgfx:dwgraphicsclass, game:gameclass, map:mapclass, obj:entityclass, help:helpclass):void {
diff --git a/mobile_version/src/edlevelclass.as b/mobile_version/src/edlevelclass.as
index 19f18a8f..56f96300 100644
--- a/mobile_version/src/edlevelclass.as
+++ b/mobile_version/src/edlevelclass.as
@@ -1,9 +1,4 @@
package {
- import flash.display.*;
- import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
-
public class edlevelclass{
public function edlevelclass():void {
clear();
diff --git a/mobile_version/src/entclass.as b/mobile_version/src/entclass.as
index c95c3e6e..d8e65ddf 100644
--- a/mobile_version/src/entclass.as
+++ b/mobile_version/src/entclass.as
@@ -1,10 +1,7 @@
-package {
- import flash.display.*;
+package {
import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
- public class entclass extends Sprite {
+ public class entclass{
public function entclass():void {
clear();
}
diff --git a/mobile_version/src/entityclass.as b/mobile_version/src/entityclass.as
index d1deaed8..813f7154 100644
--- a/mobile_version/src/entityclass.as
+++ b/mobile_version/src/entityclass.as
@@ -1,11 +1,8 @@
-package {
+package {
import bigroom.input.KeyPoll;
- import flash.display.*;
import flash.geom.*;
- import flash.events.*;
- import flash.net.*;
-
- public class entityclass extends Sprite {
+
+ public class entityclass {
static public var BLOCK:Number = 0;
static public var TRIGGER:Number = 1;
static public var DAMAGE:Number = 2;
@@ -587,8 +584,8 @@
break;
case TRIGGER: //Trigger
blocks[k].type = TRIGGER;
- blocks[k].x = xp;
- blocks[k].y = yp;
+ blocks[k].xp = xp;
+ blocks[k].yp = yp;
blocks[k].wp = w;
blocks[k].hp = h;
blocks[k].rectset(xp, yp, w, h);
@@ -598,8 +595,8 @@
break;
case DAMAGE: //Damage
blocks[k].type = DAMAGE;
- blocks[k].x = xp;
- blocks[k].y = yp;
+ blocks[k].xp = xp;
+ blocks[k].yp = yp;
blocks[k].wp = w;
blocks[k].hp = h;
blocks[k].rectset(xp, yp, w, h);
@@ -608,8 +605,8 @@
break;
case DIRECTIONAL: //Directional
blocks[k].type = DIRECTIONAL;
- blocks[k].x = xp;
- blocks[k].y = yp;
+ blocks[k].xp = xp;
+ blocks[k].yp = yp;
blocks[k].wp = w;
blocks[k].hp = h;
blocks[k].rectset(xp, yp, w, h);
@@ -629,8 +626,8 @@
break;
case ACTIVITY: //Activity Zone
blocks[k].type = ACTIVITY;
- blocks[k].x = xp;
- blocks[k].y = yp;
+ blocks[k].xp = xp;
+ blocks[k].yp = yp;
blocks[k].wp = w;
blocks[k].hp = h;
blocks[k].rectset(xp, yp, w, h);
@@ -816,19 +813,19 @@
trig=0;
break;
case 25:
- blocks[k].prompt = "Passion for Exploring";
+ blocks[k].prompt = "Passion for exploring";
blocks[k].script = "terminal_juke1";
setblockcolour(k, "orange");
trig=0;
break;
case 26:
- blocks[k].prompt = "Pushing Onwards";
+ blocks[k].prompt = "Pushing onwards";
blocks[k].script = "terminal_juke2";
setblockcolour(k, "orange");
trig=0;
break;
case 27:
- blocks[k].prompt = "Positive Force";
+ blocks[k].prompt = "Positive force";
blocks[k].script = "terminal_juke3";
setblockcolour(k, "orange");
trig=0;
@@ -840,13 +837,13 @@
trig=0;
break;
case 29:
- blocks[k].prompt = "Potential for Anything";
+ blocks[k].prompt = "Potential for anything";
blocks[k].script = "terminal_juke5";
setblockcolour(k, "orange");
trig=0;
break;
case 30:
- blocks[k].prompt = "Predestined Fate";
+ blocks[k].prompt = "Predestined fate";
blocks[k].script = "terminal_juke6";
setblockcolour(k, "orange");
trig=0;
@@ -870,7 +867,7 @@
trig=0;
break;
case 34:
- blocks[k].prompt = "ecroF evitisoP";
+ blocks[k].prompt = "ecrof evitisoP";
blocks[k].script = "terminal_juke10";
setblockcolour(k, "orange");
trig=0;
@@ -1276,7 +1273,7 @@
entities[k].gravity = true;
break;
- case 1: //Simple enemy, bouncing off the walls
+ case 1:
entities[k].rule = 1;
entities[k].xp = xp; entities[k].yp = yp;
entities[k].behave = vx; entities[k].para = vy;
@@ -3790,14 +3787,14 @@
colpoint1.x = entities[i].xp; colpoint1.y = entities[i].yp;
colpoint2.x = entities[j].xp; colpoint2.y = entities[j].yp;
if (dwgfx.flipmode) {
- if (dwgfx.flipsprites[entities[i].drawframe].hitTest(
- colpoint1, 1, dwgfx.flipsprites[entities[j].drawframe], colpoint2, 1)) {
+ if (dwgfx.flipsprites_bitmap[entities[i].drawframe].hitTest(
+ colpoint1, 1, dwgfx.flipsprites_bitmap[entities[j].drawframe], colpoint2, 1)) {
//Do the collision stuff
game.deathseq = 30;
}
- }else{
- if (dwgfx.sprites[entities[i].drawframe].hitTest(
- colpoint1, 1, dwgfx.sprites[entities[j].drawframe], colpoint2, 1)) {
+ }else {
+ if (dwgfx.sprites_bitmap[entities[i].drawframe].hitTest(
+ colpoint1, 1, dwgfx.sprites_bitmap[entities[j].drawframe], colpoint2, 1)) {
//Do the collision stuff
game.deathseq = 30;
}
@@ -3851,9 +3848,9 @@
if (entities[j].onentity > 0) {
//ok; only check the actual collision if they're in a close proximity
temp = entities[i].yp - entities[j].yp;
- if (temp > -30 && temp < 30) {
+ if (temp < 30 || temp > -30) {
temp = entities[i].xp - entities[j].xp;
- if (temp > -30 && temp < 30) {
+ if (temp < 30 || temp > -30) {
if (entitycollide(i, j)) entities[j].state = entities[j].onentity;
}
}
@@ -3890,14 +3887,14 @@
colpoint1.x = entities[i].xp; colpoint1.y = entities[i].yp;
colpoint2.x = entities[j].xp; colpoint2.y = entities[j].yp;
if (dwgfx.flipmode) {
- if (dwgfx.flipsprites[entities[i].drawframe].hitTest(
- colpoint1, 1, dwgfx.flipsprites[entities[j].drawframe], colpoint2, 1)) {
+ if (dwgfx.flipsprites_bitmap[entities[i].drawframe].hitTest(
+ colpoint1, 1, dwgfx.flipsprites_bitmap[entities[j].drawframe], colpoint2, 1)) {
//Do the collision stuff
game.deathseq = 30; game.scmhurt = true;
}
- }else{
- if (dwgfx.sprites[entities[i].drawframe].hitTest(
- colpoint1, 1, dwgfx.sprites[entities[j].drawframe], colpoint2, 1)) {
+ }else {
+ if (dwgfx.sprites_bitmap[entities[i].drawframe].hitTest(
+ colpoint1, 1, dwgfx.sprites_bitmap[entities[j].drawframe], colpoint2, 1)) {
//Do the collision stuff
game.deathseq = 30; game.scmhurt = true;
}
@@ -4019,4 +4016,4 @@
public var mobilemenus:Boolean = true;
}
-}
+}
\ No newline at end of file
diff --git a/mobile_version/src/gameclass.as b/mobile_version/src/gameclass.as
index 2f487b8f..e2e69729 100644
--- a/mobile_version/src/gameclass.as
+++ b/mobile_version/src/gameclass.as
@@ -325,7 +325,7 @@
//These coordinates now need to be translated to actual screen coordinates
//Gamecenter
if(menustart && !showloadingnotice) {
- if (inbox(m_touchx, m_touchy, 0, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing * 2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing * 2))) {
+ if (inbox(m_touchx, m_touchy, 0, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing * 2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing * 2))) {
//Bring up game center achievements
scores.showAchievements();
}
@@ -465,11 +465,11 @@
m_touchy = key.touchy[key.touchPoints - 1];
if (dwgfx.flipmode) m_touchy = dwgfx.devicey - m_touchy;
- if (inbox(m_touchx, m_touchy, dwgfx.devicex - dwgfx.buttonscreen[0].width - dwgfx.buttonxspacing, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing*2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing*2) )) {
+ if (inbox(m_touchx, m_touchy, dwgfx.devicex - dwgfx.button_image_width[0] - dwgfx.buttonxspacing, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing*2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing*2) )) {
press_map = true;
}
if(menupage == 0){
- if (inbox(m_touchx, m_touchy, 0, 0, dwgfx.buttonscreen[1].width + (dwgfx.buttonxspacing*2), dwgfx.buttonscreen[1].height + (dwgfx.buttonyspacing*2) )) {
+ if (inbox(m_touchx, m_touchy, 0, 0, dwgfx.button_image_width[1] + (dwgfx.buttonxspacing*2), dwgfx.button_image_height[1] + (dwgfx.buttonyspacing*2) )) {
menupage = 30;
music.playef(11, 10);
}
@@ -646,12 +646,12 @@
}else
*/
if (insecretlab) {
- if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing * 2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing * 2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing * 2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing * 2) )) {
scores.opengamecenter();
press_map = true;
}
}
- if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.buttonscreen[0].width - dwgfx.buttonxspacing, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing*2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing*2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.button_image_width[0] - dwgfx.buttonxspacing, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing*2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing*2) )) {
press_map = true;
}else {
if (key.touchid[i] != key.controlstick) {
@@ -670,12 +670,12 @@
// press_action = true;
//}else
if (insecretlab) {
- if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing * 2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing * 2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing * 2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing * 2) )) {
scores.opengamecenter();
press_map = true;
}
}
- if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.buttonscreen[0].width - dwgfx.buttonxspacing, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing*2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing*2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.button_image_width[0] - dwgfx.buttonxspacing, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing*2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing*2) )) {
press_map = true;
}else{
if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.devicex / 2, dwgfx.devicey)) {
@@ -729,12 +729,12 @@
//D-Pad controls
for (i = 0; i < key.touchPoints; i++) {
if (insecretlab) {
- if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing * 2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing * 2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], 0, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing * 2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing * 2) )) {
scores.opengamecenter();
press_map = true;
}
}
- if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.buttonscreen[0].width - dwgfx.buttonxspacing, 0, dwgfx.buttonscreen[0].width + (dwgfx.buttonxspacing*2), dwgfx.buttonscreen[0].height + (dwgfx.buttonyspacing*2) )) {
+ if (inbox(key.touchx[i], key.touchy[i], dwgfx.devicex - dwgfx.button_image_width[0] - dwgfx.buttonxspacing, 0, dwgfx.button_image_width[0] + (dwgfx.buttonxspacing*2), dwgfx.button_image_height[0] + (dwgfx.buttonyspacing*2) )) {
press_map = true;
}else if (inbox(key.touchx[i], key.touchy[i], 0, dwgfx.buttonpos[2].y - (dwgfx.devicey*2/3), dwgfx.buttonsize + dwgfx.buttonxspacing+ (dwgfx.buttonxspacing/2), dwgfx.devicey)) {
press_left = true;
diff --git a/mobile_version/src/helpclass.as b/mobile_version/src/helpclass.as
index 59f0b59b..5c2c723b 100644
--- a/mobile_version/src/helpclass.as
+++ b/mobile_version/src/helpclass.as
@@ -1,11 +1,11 @@
-package {
+package {
import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.net.*;
import flash.system.System;
- public class helpclass extends Sprite {
+ public class helpclass{
public function init():void {
sine = new Array();
cosine = new Array();
diff --git a/mobile_version/src/includes/input.as b/mobile_version/src/includes/input.as
index 5c792a83..91f170e2 100644
--- a/mobile_version/src/includes/input.as
+++ b/mobile_version/src/includes/input.as
@@ -239,8 +239,8 @@ public function titleinput(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, gam
}else if (game.currentmenuoption == 4) {
//More games (external link)
music.playef(11, 10);
- var distractionware_link:URLRequest = new URLRequest( "http://distractionware.com/games/ios/" );
- //var distractionware_link:URLRequest = new URLRequest( "http://distractionware.com/games/android/" );
+ //var distractionware_link:URLRequest = new URLRequest( "http://distractionware.com/games/ios/" );
+ var distractionware_link:URLRequest = new URLRequest( "http://distractionware.com/games/android/" );
navigateToURL( distractionware_link, "_blank" );
}
}else{
@@ -649,7 +649,7 @@ public function titleinput(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, gam
}
}else if (game.currentmenuname == "unlockmenu") {
if (game.currentmenuoption == 0) {
- //unlock time trials separately...
+ //unlock time trials seperately...
music.playef(11, 10);
game.createmenu("unlockmenutrials");
map.nexttowercolour();
@@ -1337,7 +1337,7 @@ public function gameinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
game.gamestate = 5;
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.resumegamemode = false;
game.useteleporter = true;
@@ -1371,7 +1371,7 @@ public function gameinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
game.gamestate = MAPMODE;
game.gamesaved = false; dwgfx.resumegamemode = false;
game.menupage = 20; // The Map Page
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
}else if (game.intimetrial && dwgfx.fademode == 0) {
@@ -1382,7 +1382,7 @@ public function gameinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
game.gamestate = MAPMODE;
game.gamesaved = false; dwgfx.resumegamemode = false;
game.menupage = 10; // The Map Page
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
}else{
@@ -1399,7 +1399,7 @@ public function gameinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
map.cursordelay = 0; map.cursorstate = 0;
game.gamesaved = false; dwgfx.resumegamemode = false;
game.menupage = 0; // The Map Page
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
}
@@ -1411,7 +1411,7 @@ public function gameinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
game.gamestate = MAPMODE;
game.gamesaved = false; dwgfx.resumegamemode = false;
game.menupage = 10; // The Map Page
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
}
@@ -1553,7 +1553,7 @@ public function mapinput(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map
}
if (dwgfx.fademode == 1) {
- dwgfx.menubuffer.fillRect(dwgfx.menubuffer.rect, 0x000000);
+ dwgfx.clear_menubuffer();
dwgfx.resumegamemode = true;
obj.removeallblocks();
game.menukludge = false;
diff --git a/mobile_version/src/includes/logic.as b/mobile_version/src/includes/logic.as
index 4993a378..46fd3af2 100644
--- a/mobile_version/src/includes/logic.as
+++ b/mobile_version/src/includes/logic.as
@@ -465,7 +465,7 @@ public function gamelogic(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
if (obj.entities[i].type == 2 && obj.entities[i].state == 3) {
//Ok! super magical exception for the room with the intention death for the shiny trinket
//fix this when the maps are finalised
- if (game.roomx != 111 || game.roomy != 107 || map.custommode) {
+ if (game.roomx != 111 && game.roomy != 107) {
obj.entities[i].state = 4;
}else {
obj.entities[i].state = 4;
diff --git a/mobile_version/src/includes/render.as b/mobile_version/src/includes/render.as
index 72dd7872..6d4d653f 100644
--- a/mobile_version/src/includes/render.as
+++ b/mobile_version/src/includes/render.as
@@ -1,11 +1,12 @@
import flash.geom.Point;
+import starling.textures.Texture;
public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, game:gameclass, obj:entityclass, help:helpclass):void {
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
- dwgfx.backbuffer.fillRect(dwgfx.backbuffer.rect, 0x000000);
+ //dwgfx.backbuffer.lock();
if (!game.menustart) {
+ dwgfx.cls(0x000000);
tr = 164 - (help.glow / 2) - Math.random() * 4;
tg = 164 - (help.glow / 2) - Math.random() * 4;
tb = 164 - (help.glow / 2) - Math.random() * 4;
@@ -26,9 +27,10 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
/*dwgfx.print(5, 5, "IGF WIP Build, 29th Oct '09", tr, tg, tb, true);
dwgfx.print(5, 200, "Game by Terry Cavanagh", tr, tg, tb, true);
- dwgfx.print(5, 210, "Music by Magnus P~lsson", tr, tg, tb, true);
+ dwgfx.print(5, 210, "Music by Magnus Palsson", tr, tg, tb, true);
dwgfx.print(5, 220, "Roomnames by Bennett Foddy", tr, tg, tb, true);*/
}else {
+ dwgfx.cls(dwgfx.tower_bgdarkcol[map.colstate]);
if(!game.colourblindmode) dwgfx.drawtowerbackgroundsolo(map);
tr = map.r - (help.glow / 4) - Math.random() * 4;
@@ -39,8 +41,7 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
if (tb < 0) tb = 0; if(tb>255) tb=255;
temp = 30+20;
-
- if(game.currentmenuname=="mainmenu"){
+ if (game.currentmenuname == "mainmenu") {
dwgfx.drawsprite((160 - 96) + 0 * 32, temp, 23, tr, tg, tb);
dwgfx.drawsprite((160 - 96) + 1 * 32, temp, 23, tr, tg, tb);
dwgfx.drawsprite((160 - 96) + 2 * 32, temp, 23, tr, tg, tb);
@@ -116,7 +117,7 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
//dwgfx.print( 40, 85, "http://www.distractionware.com", tr, tg, tb, true);
dwgfx.print( -1, 120, "and features music by", tr, tg, tb, true);
- dwgfx.bigprint( 40, 135, "Magnus P~lsson", tr, tg, tb, true, 2);
+ dwgfx.bigprint( 40, 135, "Magnus Palsson", tr, tg, tb, true, 2);
dwgfx.drawimagecol(8, -1, 156, tr *0.75, tg *0.75, tb *0.75, true);
//dwgfx.print( 40, 155, "http://souleye.madtracker.net", tr, tg, tb, true);
}else if (game.currentmenuname == "credits2") {
@@ -199,7 +200,7 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
dwgfx.print( 80, 80,"Joshua Buergel", tr, tg, tb);
dwgfx.print( 80, 90,"Joshua Hochner", tr, tg, tb);
dwgfx.print( 80, 100,"Kurt Ostfeld", tr, tg, tb);
- dwgfx.print( 80, 110,"Magnus P~lsson", tr, tg, tb);
+ dwgfx.print( 80, 110,"Magnus Palsson", tr, tg, tb);
dwgfx.print( 80, 120,"Mark Neschadimenko", tr, tg, tb);
dwgfx.print( 80, 130,"Matt Antonellis", tr, tg, tb);
dwgfx.print( 80, 140,"Matthew Reppert", tr, tg, tb);
@@ -483,7 +484,7 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
/*
dwgfx.bigprint( -1, 30, "Unlock Time Trials", tr, tg, tb, true);
dwgfx.print( -1, 65, "You can unlock each time", tr, tg, tb, true);
- dwgfx.print( -1, 75, "trial separately.", tr, tg, tb, true);
+ dwgfx.print( -1, 75, "trial seperately.", tr, tg, tb, true);
*/
}else if (game.currentmenuname == "timetrials") {
/*
@@ -688,27 +689,27 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
}else if (game.currentmenuname == "unlocktimetrial") {
dwgfx.bigprint( -1, 45, "Congratulations!", tr, tg, tb, true, 2);
- dwgfx.print( -1, 125, "You have unlocked", tr, tg, tb, true);
+ dwgfx.print( -1, 125, "Your have unlocked", tr, tg, tb, true);
dwgfx.print( -1, 135, "a new Time Trial.", tr, tg, tb, true);
}else if (game.currentmenuname == "unlocktimetrials") {
dwgfx.bigprint( -1, 45, "Congratulations!", tr, tg, tb, true, 2);
- dwgfx.print( -1, 125, "You have unlocked some", tr, tg, tb, true);
+ dwgfx.print( -1, 125, "Your have unlocked some", tr, tg, tb, true);
dwgfx.print( -1, 135, "new Time Trials.", tr, tg, tb, true);
}else if (game.currentmenuname == "unlocknodeathmode") {
dwgfx.bigprint( -1, 45, "Congratulations!", tr, tg, tb, true, 2);
- dwgfx.print( -1, 125, "You have unlocked", tr, tg, tb, true);
+ dwgfx.print( -1, 125, "Your have unlocked", tr, tg, tb, true);
dwgfx.print( -1, 135, "No Death Mode.", tr, tg, tb, true);
}else if (game.currentmenuname == "unlockflipmode") {
dwgfx.bigprint( -1, 45, "Congratulations!", tr, tg, tb, true, 2);
- dwgfx.print( -1, 125, "You have unlocked", tr, tg, tb, true);
+ dwgfx.print( -1, 125, "Your have unlocked", tr, tg, tb, true);
dwgfx.print( -1, 135, "Flip Mode.", tr, tg, tb, true);
}else if (game.currentmenuname == "unlockintermission") {
dwgfx.bigprint( -1, 45, "Congratulations!", tr, tg, tb, true, 2);
- dwgfx.print( -1, 125, "You have unlocked", tr, tg, tb, true);
+ dwgfx.print( -1, 125, "Your have unlocked", tr, tg, tb, true);
dwgfx.print( -1, 135, "the intermission levels.", tr, tg, tb, true);
}
@@ -784,14 +785,14 @@ public function titlerender(key:KeyPoll, dwgfx:dwgraphicsclass, map:mapclass, ga
}else{
dwgfx.render();
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
-public function gamecompleterender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, obj:entityclass, help:helpclass):void {
+public function gamecompleterender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass, obj:entityclass, help:helpclass):void {
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
- dwgfx.backbuffer.fillRect(dwgfx.backbuffer.rect, 0x000000);
+ //dwgfx.backbuffer.lock();
+ dwgfx.cls(dwgfx.tower_bgdarkcol[map.colstate]);
if(!game.colourblindmode) dwgfx.drawtowerbackgroundsolo(map);
//dwgfx.drawtowermap(map);
@@ -856,7 +857,7 @@ public function gamecompleterender(key:KeyPoll, dwgfx:dwgraphicsclass, game:game
if (dwgfx.onscreen(640 + game.creditposition)) {
dwgfx.print(40, 640 + game.creditposition, "With Music by", tr, tg, tb);
- dwgfx.bigprint(60, 650 + game.creditposition, "Magnus P~lsson", tr, tg, tb);
+ dwgfx.bigprint(60, 650 + game.creditposition, "Magnus Palsson", tr, tg, tb);
}
if (dwgfx.onscreen(680 + game.creditposition)) {
@@ -934,7 +935,7 @@ if (dwgfx.onscreen(1410 + game.creditposition)) dwgfx.print(-1, 1420 + game.cred
if (dwgfx.onscreen(1420 + game.creditposition)) dwgfx.print(-1, 1430 + game.creditposition,"Joshua Buergel", tr, tg, tb, true);
if (dwgfx.onscreen(1430 + game.creditposition)) dwgfx.print(-1, 1440 + game.creditposition,"Joshua Hochner", tr, tg, tb, true);
if (dwgfx.onscreen(1440 + game.creditposition)) dwgfx.print(-1, 1450 + game.creditposition,"Kurt Ostfeld", tr, tg, tb, true);
-if (dwgfx.onscreen(1450 + game.creditposition)) dwgfx.print(-1, 1460 + game.creditposition, "Magnus P~lsson", tr, tg, tb, true);
+if (dwgfx.onscreen(1450 + game.creditposition)) dwgfx.print(-1, 1460 + game.creditposition, "Magnus Palsson", tr, tg, tb, true);
if (dwgfx.onscreen(1460 + game.creditposition)) dwgfx.print(-1, 1470 + game.creditposition,"Mark Neschadimenko", tr, tg, tb, true);
if (dwgfx.onscreen(1470 + game.creditposition)) dwgfx.print(-1, 1480 + game.creditposition,"Matt Antonellis", tr, tg, tb, true);
if (dwgfx.onscreen(1480 + game.creditposition)) dwgfx.print(-1, 1490 + game.creditposition,"Matthew Reppert", tr, tg, tb, true);
@@ -971,14 +972,14 @@ if (dwgfx.onscreen(1760 + game.creditposition)) dwgfx.bigprint( -1, 1760 + game.
}else{
dwgfx.render();
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function gamecompleterender2(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, obj:entityclass, help:helpclass):void {
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
- dwgfx.backbuffer.fillRect(dwgfx.backbuffer.rect, 0x000000);
+ //dwgfx.backbuffer.lock();
+ dwgfx.cls(0x000000);
dwgfx.drawimage(10, 0, 0);
@@ -1013,7 +1014,7 @@ public function gamecompleterender2(key:KeyPoll, dwgfx:dwgraphicsclass, game:gam
}else{
dwgfx.render();
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function gamerender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass,
@@ -1021,7 +1022,7 @@ public function gamerender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, m
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
+ //dwgfx.backbuffer.lock();
if(!game.blackout){
if(!game.colourblindmode) dwgfx.drawbackground(map.background, map);
@@ -1050,6 +1051,8 @@ public function gamerender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, m
}
dwgfx.drawentities(map, obj, help);
+ }else {
+ dwgfx.cls(0x000000);
}
/*for(i=0; i 100 && !game.advancetext && game.hascontrol && !script.running && !game.intimetrial) {
i = obj.getplayer();
if(dwgfx.flipmode){
- dwgfx.bprint(5, 20, "- Press ENTER to Teleport -", game.readytotele - 20 - (help.glow / 2), game.readytotele - 20 - (help.glow / 2), game.readytotele, true);
+ dwgfx.print(5, 20, "- Press ENTER to Teleport -", game.readytotele - 20 - (help.glow / 2), game.readytotele - 20 - (help.glow / 2), game.readytotele, true);
}else {
- dwgfx.bprint(5, 210, "- Press ENTER to Teleport -", game.readytotele - 20 - (help.glow / 2), game.readytotele - 20 - (help.glow / 2), game.readytotele, true);
+ dwgfx.print(5, 210, "- Press ENTER to Teleport -", game.readytotele - 20 - (help.glow / 2), game.readytotele - 20 - (help.glow / 2), game.readytotele, true);
}
}
}
@@ -1304,7 +1307,7 @@ public function gamerender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, m
dwgfx.render();
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass,
@@ -1312,13 +1315,14 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
+ //dwgfx.backbuffer.lock();
//dwgfx.drawgui(help);
//draw screen alliteration
//Roomname:
+ dwgfx.drawfillrect(0, 0, 320, 12, 0, 0, 0);
temp = map.area(game.roomx, game.roomy);
if (temp < 2 && !map.custommode && dwgfx.fademode == 0) {
if (game.roomx >= 102 && game.roomx <= 104 && game.roomy >= 110 && game.roomy <= 111) {
@@ -1343,19 +1347,17 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
dwgfx.crewframedelay = 8;
dwgfx.crewframe = (dwgfx.crewframe + 1) % 2;
}
-
- //Menubar:
- dwgfx.drawtextbox( -10, 212, 42, 3, 65, 185, 207);
- switch(game.menupage) {
+ //Menubar:
+ //dwgfx.drawtextbox( -10, 212, 42, 3, 65, 185, 207);
+ dwgfx.drawfillrect(0, 212, 320, 24, 11, 31, 35);
+ dwgfx.drawfillrect(0, 212, 320, 2, 65, 185, 207);
+ dwgfx.drawfillrect(0, 215, 320, 1, 65, 185, 207);
+ dwgfx.drawfillrect(0, 230, 320, 1, 65, 185, 207);
+ dwgfx.drawfillrect(0, 232, 320, 2, 65, 185, 207);
+
+ switch(game.menupage) {
case 0:
- dwgfx.print(30 - 8, 220, "[MAP]", 196, 196, 255 - help.glow);
- if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
- }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
- }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 65, 185, 207);
if (game.insecretlab) { dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "GRAV", 32, 92, 104);
@@ -1363,6 +1365,13 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}else{ dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "CREW", 32, 92, 104);}
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30 - 8, 220, "[MAP]", 196, 196, 255 - help.glow);
+ if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
+ }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
+ }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (map.finalmode || (map.custommode && !map.customshowmm)) {
@@ -1379,7 +1388,7 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}else if(map.custommode){
//draw the map image
dwgfx.drawcustompixeltextbox(35 + map.custommmxoff, 16 + map.custommmyoff, map.custommmxsize + 10, map.custommmysize + 10, (map.custommmxsize + 10) / 8, (map.custommmysize + 10) / 8, 65, 185, 207, 4, 0);
- dwgfx.drawpartimage(12, 40 + map.custommmxoff, 21 + map.custommmyoff, map.custommmxsize, map.custommmysize);
+ dwgfx.drawpartimage(dwgfx.customminimap as Texture, 40 + map.custommmxoff, 21 + map.custommmyoff, map.custommmxsize, map.custommmysize);
//Black out here
if(map.customzoom==4){
@@ -1564,16 +1573,16 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
break;
case 1:
if (game.insecretlab) {
- dwgfx.print(30, 220, "MAP", 64,64,64);
- dwgfx.print(103-8, 220, "[GRAV]", 196, 196, 255 - help.glow);
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "GRAV", 65, 185, 207);
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ dwgfx.print(103-8, 220, "[GRAV]", 196, 196, 255 - help.glow);
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (dwgfx.flipmode) {
@@ -1610,16 +1619,16 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}
}
}else if (obj.flags[67] == 1 && !map.custommode) {
- dwgfx.print(30, 220, "MAP", 64,64,64);
- dwgfx.print(103-8, 220, "[SHIP]", 196, 196, 255 - help.glow);
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "SHIP", 65, 185, 207);
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ dwgfx.print(103-8, 220, "[SHIP]", 196, 196, 255 - help.glow);
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (game.mobilemenu) {
@@ -1635,16 +1644,16 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
dwgfx.print(0, 105, "Press ACTION to warp to the ship.", 196, 196, 255 - help.glow, true);
}
}else if(map.custommode){
- dwgfx.print(30, 220, "MAP", 64,64,64);
- dwgfx.print(103-8, 220, "[CREW]", 196, 196, 255 - help.glow);
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "CREW", 65, 185, 207);
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ dwgfx.print(103-8, 220, "[CREW]", 196, 196, 255 - help.glow);
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (dwgfx.flipmode){
@@ -1675,16 +1684,16 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}
}
}else{
- dwgfx.print(30, 220, "MAP", 64,64,64);
- dwgfx.print(103-8, 220, "[CREW]", 196, 196, 255 - help.glow);
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "CREW", 65, 185, 207);
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ dwgfx.print(103-8, 220, "[CREW]", 196, 196, 255 - help.glow);
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (dwgfx.flipmode) {
@@ -1731,20 +1740,20 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}
break;
case 2:
- dwgfx.print(30, 220, "MAP", 64,64,64);
- if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
- }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
- }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
- dwgfx.print(185-12, 220, "[STATS]", 196, 196, 255 - help.glow);
- dwgfx.print(258, 220, "SAVE", 64, 64, 64);
-
- if (game.mobilemenu) {
+ if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
if (game.insecretlab) { dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "GRAV", 32, 92, 104);
}else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "SHIP", 32, 92, 104);
}else{ dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "CREW", 32, 92, 104);}
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 65, 185, 207);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 32, 92, 104);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
+ }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
+ }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
+ dwgfx.print(185-12, 220, "[STATS]", 196, 196, 255 - help.glow);
+ dwgfx.print(258, 220, "SAVE", 64, 64, 64);
}
if (map.custommode) {
@@ -1790,13 +1799,6 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}
break;
case 3:
- dwgfx.print(30, 220, "MAP", 64,64,64);
- if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
- }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
- }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
- dwgfx.print(185-4, 220, "STATS", 64,64,64);
- dwgfx.print(258 - 8, 220, "[SAVE]", 196, 196, 255 - help.glow);
-
if (game.mobilemenu) {
dwgfx.drawmobilebutton(game, 30 - 8, 220, 56, dwgfx.b_size, "MAP", 32, 92, 104);
if (game.insecretlab) { dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "GRAV", 32, 92, 104);
@@ -1804,6 +1806,13 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}else{ dwgfx.drawmobilebutton(game, 103, 220, 56, dwgfx.b_size, "CREW", 32, 92, 104);}
dwgfx.drawmobilebutton(game, 185-4, 220, 56, dwgfx.b_size, "STATS", 32, 92, 104);
dwgfx.drawmobilebutton(game, 258, 220, 56, dwgfx.b_size, "QUIT", 65, 185, 207);
+ }else {
+ dwgfx.print(30, 220, "MAP", 64,64,64);
+ if (game.insecretlab) { dwgfx.print(103, 220, "GRAV", 64, 64, 64);
+ }else if (obj.flags[67] == 1 && !map.custommode) { dwgfx.print(103, 220, "SHIP", 64,64,64);
+ }else{ dwgfx.print(103, 220, "CREW", 64,64,64);}
+ dwgfx.print(185-4, 220, "STATS", 64,64,64);
+ dwgfx.print(258 - 8, 220, "[SAVE]", 196, 196, 255 - help.glow);
}
dwgfx.print(0, 80, "Quit to main menu?", 255 - (help.glow * 2), 255 - (help.glow * 2), 255 - help.glow, true);
@@ -2140,21 +2149,20 @@ public function maprender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, ma
}
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function towerrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass,
obj:entityclass, help:helpclass):void {
-
dwgfx.drawbutton(game, help);
//Couple of changes for the towermode
- dwgfx.backbuffer.lock();
- dwgfx.backbuffer.fillRect(dwgfx.backbuffer.rect, 0x000000);
+ //dwgfx.backbuffer.lock();
+ dwgfx.cls(dwgfx.tower_bgdarkcol[map.colstate]);
if (!game.colourblindmode) {
dwgfx.drawtowerbackground(map);
- dwgfx.drawtowermap(map);
+ dwgfx.drawtowermap(game, map);
}else {
dwgfx.drawtowermap_nobackground(map);
}
@@ -2191,12 +2199,12 @@ public function towerrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass,
dwgfx.drawgui(help);
if (dwgfx.flipmode) {
- if (game.advancetext) dwgfx.bprint(5, 228, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ if (game.advancetext) dwgfx.print(5, 228, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}else{
- if (game.advancetext) dwgfx.bprint(5, 5, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ if (game.advancetext) dwgfx.print(5, 5, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}
- dwgfx.backbuffer.fillRect(dwgfx.footerrect, 0x000000);
+ dwgfx.drawfillrect(dwgfx.footerrect.x, dwgfx.footerrect.y, dwgfx.footerrect.width, dwgfx.footerrect.height, 0);
dwgfx.print(5, 231, map.roomname, 196, 196, 255 - help.glow, true);
//dwgfx.rprint(5, 231, String(game.coins), 255 - help.glow/2, 255 - help.glow/2, 196, true);
@@ -2259,17 +2267,18 @@ public function towerrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass,
}
dwgfx.render();
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function teleporterrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass,
obj:entityclass, help:helpclass):void {
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
+ //dwgfx.backbuffer.lock();
//draw screen alliteration
//Roomname:
+ dwgfx.drawfillrect(0, 0, 320, 12, 0, 0, 0);
temp = map.area(game.roomx, game.roomy);
if (temp < 2 && !map.custommode && dwgfx.fademode==0) {
if (game.roomx >= 102 && game.roomx <= 104 && game.roomy >= 110 && game.roomy <= 111) {
@@ -2364,9 +2373,9 @@ public function teleporterrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gamecl
dwgfx.drawgui(help);
if (dwgfx.flipmode) {
- if (game.advancetext) dwgfx.bprint(5, 228, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ if (game.advancetext) dwgfx.print(5, 228, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}else{
- if (game.advancetext) dwgfx.bprint(5, 5, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ if (game.advancetext) dwgfx.print(5, 5, "- Tap screen to advance text -", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}
@@ -2410,14 +2419,14 @@ public function teleporterrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gamecl
}
}
- dwgfx.backbuffer.unlock();
+ //dwgfx.backbuffer.unlock();
}
public function controltutorialrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:gameclass, map:mapclass,
obj:entityclass, help:helpclass):void {
dwgfx.drawbutton(game, help);
- dwgfx.backbuffer.lock();
+ //dwgfx.backbuffer.lock();
//Background color
dwgfx.drawfillrect(0, 0, 320, 240, 10, 24, 26);
@@ -2444,12 +2453,12 @@ public function controltutorialrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:g
dwgfx.print(5, 10, "-= TOUCHSCREEN CONTROLS =-", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
if(game.controltutorialstate>=3 &&game.controltutorialstate<=6){
- dwgfx.print(5, 195, "Swipe and hold on the left side", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
- dwgfx.print(5, 205, "of the screen to move", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ dwgfx.print(5, 195 + 8, "Swipe and hold on the left side", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ dwgfx.print(5, 205 + 8, "of the screen to move", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}
if(game.controltutorialstate>=7 &&game.controltutorialstate<=11){
- dwgfx.print(5, 200, "Tap on the right to flip", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
+ dwgfx.print(5, 200 + 8, "Tap on the right to flip", 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2), true);
}
if (game.controltutorialstate >= 13) {
@@ -2520,5 +2529,5 @@ public function controltutorialrender(key:KeyPoll, dwgfx:dwgraphicsclass, game:g
dwgfx.render();
}
- dwgfx.backbuffer.unlock();
-}
+ //dwgfx.backbuffer.unlock();
+}
\ No newline at end of file
diff --git a/mobile_version/src/includes/scripts.as b/mobile_version/src/includes/scripts.as
index 1488233f..7e3e555b 100644
--- a/mobile_version/src/includes/scripts.as
+++ b/mobile_version/src/includes/scripts.as
@@ -4710,7 +4710,7 @@
add("squeak(blue)");
add("text(blue,0,0,3)");
- add("This lab is amazing! The scientists");
+ add("This lab is amazing! The scentists");
add("who worked here know a lot more");
add("about warp technology than we do!");
add("position(blue,below)");
@@ -5819,4 +5819,4 @@
}
running = true;
-}
+}
\ No newline at end of file
diff --git a/mobile_version/src/includes/terminalscripts.as b/mobile_version/src/includes/terminalscripts.as
index bf13cefb..cd07a551 100644
--- a/mobile_version/src/includes/terminalscripts.as
+++ b/mobile_version/src/includes/terminalscripts.as
@@ -674,7 +674,7 @@
add(" NEXT UNLOCK: ");
add(" 5 Trinkets");
add("");
- add(" Pushing Onwards ");
+ add(" Pushing onwards ");
add("position(center)");
add("speak_active");
add("endtext");
@@ -687,7 +687,7 @@
add(" NEXT UNLOCK: ");
add(" 8 Trinkets");
add("");
- add(" Positive Force ");
+ add(" Positive force ");
add("position(center)");
add("speak_active");
add("endtext");
@@ -713,7 +713,7 @@
add(" NEXT UNLOCK: ");
add(" 12 Trinkets");
add("");
- add(" Potential for Anything ");
+ add(" Potential for anything ");
add("position(center)");
add("speak_active");
add("endtext");
@@ -739,7 +739,7 @@
add(" NEXT UNLOCK: ");
add(" 16 Trinkets");
add("");
- add(" Predestined Fate ");
+ add(" Predestined fate ");
add("position(center)");
add("speak_active");
add("endtext");
@@ -813,4 +813,4 @@
add("squeak(terminal)");
add("jukebox(10)");
}
-}
+}
\ No newline at end of file
diff --git a/mobile_version/src/mapclass.as b/mobile_version/src/mapclass.as
index 3ee1ddfd..692ce9ef 100644
--- a/mobile_version/src/mapclass.as
+++ b/mobile_version/src/mapclass.as
@@ -1,10 +1,9 @@
-package {
- import flash.display.*;
+package {
import flash.geom.*;
import flash.events.*;
import flash.net.*;
- public class mapclass extends Sprite {
+ public class mapclass {
public function mapclass():void {
//Start here!
r = 196; g = 196; b = 196;
@@ -612,6 +611,8 @@
game.activetele = false; game.readytotele = 0;
game.mobilequicksave_thisroom = false;
+ dwgfx.forcescreenupdates();
+
obj.opt_useblock = false;
obj.opt_usetrigger = false;
obj.opt_usedamage = false;
@@ -790,7 +791,7 @@
case 1: return "Dimension VVVVVV"; break;
case 2: return "Laboratory"; break;
case 3: return "The Tower"; break;
- case 4: return "Warp Zone"; break;
+ case 4: return "Warpzone"; break;
case 5: return "Space Station"; break;
case 6: return "Outside Dimension VVVVVV"; break;
case 7: return "Outside Dimension VVVVVV"; break;
@@ -892,7 +893,7 @@
}
}
- if (rx == 119 && ry == 108 && !custommode) {
+ if (rx == 119 && ry == 108) {
background = 5;
dwgfx.rcol = 3;
warpx = true;
@@ -1608,4 +1609,4 @@ obj.createentity(game, 72, 156, 11, 200); // (horizontal gravity line)
public var spikecount:int;
}
-}
+}
\ No newline at end of file
diff --git a/mobile_version/src/musicclass.as b/mobile_version/src/musicclass.as
index 254cd2c1..950e4aa8 100644
--- a/mobile_version/src/musicclass.as
+++ b/mobile_version/src/musicclass.as
@@ -1,9 +1,8 @@
-package {
- import flash.display.*;
+package {
import flash.media.*;
import flash.events.*;
- public class musicclass extends Sprite {
+ public class musicclass {
//For Music stuff
public function play(t:int):void {
if (currentsong !=t) {
diff --git a/mobile_version/src/platformclass.as b/mobile_version/src/platformclass.as
index fc5e0d69..06e2d7b5 100644
--- a/mobile_version/src/platformclass.as
+++ b/mobile_version/src/platformclass.as
@@ -2,13 +2,10 @@
package {
//import com.sticksports.nativeExtensions.SilentSwitch;
import flash.events.*;
- import flash.media.SoundMixer;
- import flash.media.AudioPlaybackMode;
public class platformclass {
public function init():void {
//SilentSwitch.apply();
- SoundMixer.audioPlaybackMode = AudioPlaybackMode.AMBIENT;
}
public function callonwake():void {
diff --git a/mobile_version/src/saveclass.as b/mobile_version/src/saveclass.as
index 7868839d..164fc397 100644
--- a/mobile_version/src/saveclass.as
+++ b/mobile_version/src/saveclass.as
@@ -1,10 +1,9 @@
-package {
- import flash.display.*;
+package {
import flash.geom.*;
import flash.events.*;
import flash.net.*;
- public class saveclass extends Sprite {
+ public class saveclass {
public function saveclass():void {
}
diff --git a/mobile_version/src/scoreclass.as b/mobile_version/src/scoreclass.as
index 076c5a75..bad5cc6c 100644
--- a/mobile_version/src/scoreclass.as
+++ b/mobile_version/src/scoreclass.as
@@ -1,10 +1,11 @@
package {
- import com.milkmangames.nativeextensions.ios.*;
- import com.milkmangames.nativeextensions.ios.events.*;
+ //import com.milkmangames.nativeextensions.ios.*;
+ //import com.milkmangames.nativeextensions.ios.events.*;
import flash.display.Stage;
public class scoreclass {
public function init(mystage:Stage):void {
+ /*
if (!GameCenter.isSupported()){
trace("GameCenter is not supported on this platform.");
}
@@ -32,41 +33,51 @@ package {
gameCenter.addEventListener(GameCenterErrorEvent.ACHIEVEMENT_REPORT_FAILED,onAchievementFailed);
gameCenter.addEventListener(GameCenterErrorEvent.ACHIEVEMENT_RESET_FAILED,onResetFailed);
GameCenter.gameCenter.authenticateLocalUser();
+ */
}
CONFIG::iphonemode {
/** Check Authentication */
- private function checkAuthentication():Boolean{
+ private function checkAuthentication():Boolean {
+ /*
if (!GameCenter.gameCenter.isUserAuthenticated()){
trace("not logged in!");
return false;
}
+ */
return true;
}
/** Reset Achievements */
- public function resetAchievements():void{
+ public function resetAchievements():void {
+ /*
if (!checkAuthentication()) return;
GameCenter.gameCenter.resetAchievements();
+ */
}
public function reportScore(t:int):void{
// we make sure you're logged in before bothering to report the score.
// later iOS versions may take care of waiting/resubmitting for you, but earlier ones won't.
+ /*
if (!checkAuthentication()) return;
t = t * 2; //Score is in 30 frame increments
GameCenter.gameCenter.reportScoreForCategory(t, "grp.supgravleaderboard");
+ */
}
public function opengamecenter():void {
+ /*
if (!checkAuthentication()) return;
GameCenter.gameCenter.showLeaderboardForCategory("grp.supgravleaderboard");
+ */
}
/** Show Achievements */
- public function showAchievements():void{
+ public function showAchievements():void {
+ /*
if (!checkAuthentication()) return;
//trace("showing achievements...");
@@ -75,6 +86,7 @@ package {
}catch (e:Error){
//trace("ERR showachievements:"+e.message+"/"+e.name+"/"+e.errorID);
}
+ */
}
public var vvvvvvgamecomplete:int = 0;
@@ -97,7 +109,8 @@ package {
public var vvvvvvsupgrav60:int = 17;
public var vvvvvvmaster:int = 18;
- public function reportAchievement(t:int):void{
+ public function reportAchievement(t:int):void {
+ /*
if (!checkAuthentication()) return;
// the '1.0' is a float (Number) value from 0.0-100.0 the percent completion of the achievement.
@@ -122,11 +135,13 @@ package {
case 17: GameCenter.gameCenter.reportAchievement("grp.vvvvvvsupgrav60", 100.0); break;
case 18: GameCenter.gameCenter.reportAchievement("grp.vvvvvvmaster", 100.0); break;
}
+ */
}
//
// Events
//
+ /*
private function onAuthSucceeded(e:GameCenterEvent):void
{
trace("Auth succeeded!");
@@ -176,10 +191,11 @@ package {
{
trace("failed to reset:"+e.message);
}
+ */
}
CONFIG::iphonemode {
- public var gameCenter:GameCenter;
+ //public var gameCenter:GameCenter;
public var gamecenteron:Boolean = true;
}
}
diff --git a/mobile_version/src/scriptclass.as b/mobile_version/src/scriptclass.as
index b1d12d8e..9d511365 100644
--- a/mobile_version/src/scriptclass.as
+++ b/mobile_version/src/scriptclass.as
@@ -1,13 +1,12 @@
-package {
+package {
import flash.ui.Keyboard;
- import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.net.*;
import bigroom.input.KeyPoll;
import flash.system.fscommand;
- public class scriptclass extends Sprite {
+ public class scriptclass {
public var GAMEMODE:int = 0;
public var TITLEMODE:int = 1;
public var CLICKTOSTART:int = 2;
@@ -772,7 +771,7 @@
game.gamestate = 5;
dwgfx.menuoffset = 240; //actually this should count the roomname
if (map.extrarow) dwgfx.menuoffset -= 10;
- dwgfx.menubuffer.copyPixels(dwgfx.screenbuffer, dwgfx.screenbuffer.rect, dwgfx.tl, null, null, false);
+ dwgfx.setup_menubuffer();
dwgfx.resumegamemode = false;
game.useteleporter = false; //good heavens don't actually use it
@@ -1063,7 +1062,7 @@
}else if (words[0] == "foundlab2") {
dwgfx.textboxremovefast();
- dwgfx.createtextbox("The secret lab is separate from", 50, 85, 174, 174, 174);
+ dwgfx.createtextbox("The secret lab is seperate from", 50, 85, 174, 174, 174);
dwgfx.addline("the rest of the game. You can");
dwgfx.addline("now come back here at any time");
dwgfx.addline("by selecting the new SECRET LAB");
diff --git a/mobile_version/src/starling/animation/DelayedCall.as b/mobile_version/src/starling/animation/DelayedCall.as
new file mode 100644
index 00000000..46e6e673
--- /dev/null
+++ b/mobile_version/src/starling/animation/DelayedCall.as
@@ -0,0 +1,140 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.animation
+{
+ import starling.core.starling_internal;
+ import starling.events.Event;
+ import starling.events.EventDispatcher;
+
+ /** A DelayedCall allows you to execute a method after a certain time has passed. Since it
+ * implements the IAnimatable interface, it can be added to a juggler. In most cases, you
+ * do not have to use this class directly; the juggler class contains a method to delay
+ * calls directly.
+ *
+ *
DelayedCall dispatches an Event of type 'Event.REMOVE_FROM_JUGGLER' when it is finished,
+ * so that the juggler automatically removes it when its no longer needed.
+ *
+ * @see Juggler
+ */
+ public class DelayedCall extends EventDispatcher implements IAnimatable
+ {
+ private var _currentTime:Number;
+ private var _totalTime:Number;
+ private var _callback:Function;
+ private var _args:Array;
+ private var _repeatCount:int;
+
+ /** Creates a delayed call. */
+ public function DelayedCall(callback:Function, delay:Number, args:Array=null)
+ {
+ reset(callback, delay, args);
+ }
+
+ /** Resets the delayed call to its default values, which is useful for pooling. */
+ public function reset(callback:Function, delay:Number, args:Array=null):DelayedCall
+ {
+ _currentTime = 0;
+ _totalTime = Math.max(delay, 0.0001);
+ _callback = callback;
+ _args = args;
+ _repeatCount = 1;
+
+ return this;
+ }
+
+ /** @inheritDoc */
+ public function advanceTime(time:Number):void
+ {
+ var previousTime:Number = _currentTime;
+ _currentTime += time;
+
+ if (_currentTime > _totalTime)
+ _currentTime = _totalTime;
+
+ if (previousTime < _totalTime && _currentTime >= _totalTime)
+ {
+ if (_repeatCount == 0 || _repeatCount > 1)
+ {
+ _callback.apply(null, _args);
+
+ if (_repeatCount > 0) _repeatCount -= 1;
+ _currentTime = 0;
+ advanceTime((previousTime + time) - _totalTime);
+ }
+ else
+ {
+ // save call & args: they might be changed through an event listener
+ var call:Function = _callback;
+ var args:Array = _args;
+
+ // in the callback, people might want to call "reset" and re-add it to the
+ // juggler; so this event has to be dispatched *before* executing 'call'.
+ dispatchEventWith(Event.REMOVE_FROM_JUGGLER);
+ call.apply(null, args);
+ }
+ }
+ }
+
+ /** Advances the delayed call so that it is executed right away. If 'repeatCount' is
+ * anything else than '1', this method will complete only the current iteration. */
+ public function complete():void
+ {
+ var restTime:Number = _totalTime - _currentTime;
+ if (restTime > 0) advanceTime(restTime);
+ }
+
+ /** Indicates if enough time has passed, and the call has already been executed. */
+ public function get isComplete():Boolean
+ {
+ return _repeatCount == 1 && _currentTime >= _totalTime;
+ }
+
+ /** The time for which calls will be delayed (in seconds). */
+ public function get totalTime():Number { return _totalTime; }
+
+ /** The time that has already passed (in seconds). */
+ public function get currentTime():Number { return _currentTime; }
+
+ /** The number of times the call will be repeated.
+ * Set to '0' to repeat indefinitely. @default 1 */
+ public function get repeatCount():int { return _repeatCount; }
+ public function set repeatCount(value:int):void { _repeatCount = value; }
+
+ /** The callback that will be executed when the time is up. */
+ public function get callback():Function { return _callback; }
+
+ /** The arguments that the callback will be executed with.
+ * Beware: not a copy, but the actual object! */
+ public function get arguments():Array { return _args; }
+
+ // delayed call pooling
+
+ private static var sPool:Vector. = new [];
+
+ /** @private */
+ starling_internal static function fromPool(call:Function, delay:Number,
+ args:Array=null):DelayedCall
+ {
+ if (sPool.length) return sPool.pop().reset(call, delay, args);
+ else return new DelayedCall(call, delay, args);
+ }
+
+ /** @private */
+ starling_internal static function toPool(delayedCall:DelayedCall):void
+ {
+ // reset any object-references, to make sure we don't prevent any garbage collection
+ delayedCall._callback = null;
+ delayedCall._args = null;
+ delayedCall.removeEventListeners();
+ sPool.push(delayedCall);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/animation/IAnimatable.as b/mobile_version/src/starling/animation/IAnimatable.as
new file mode 100644
index 00000000..d954426f
--- /dev/null
+++ b/mobile_version/src/starling/animation/IAnimatable.as
@@ -0,0 +1,30 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.animation
+{
+ /** The IAnimatable interface describes objects that are animated depending on the passed time.
+ * Any object that implements this interface can be added to a juggler.
+ *
+ *
When an object should no longer be animated, it has to be removed from the juggler.
+ * To do this, you can manually remove it via the method juggler.remove(object),
+ * or the object can request to be removed by dispatching a Starling event with the type
+ * Event.REMOVE_FROM_JUGGLER. The "Tween" class is an example of a class that
+ * dispatches such an event; you don't have to remove tweens manually from the juggler.
+ *
+ * @see Juggler
+ * @see Tween
+ */
+ public interface IAnimatable
+ {
+ /** Advance the time by a number of seconds. @param time in seconds. */
+ function advanceTime(time:Number):void;
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/animation/Juggler.as b/mobile_version/src/starling/animation/Juggler.as
new file mode 100644
index 00000000..810a7e82
--- /dev/null
+++ b/mobile_version/src/starling/animation/Juggler.as
@@ -0,0 +1,396 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.animation
+{
+ import flash.utils.Dictionary;
+
+ import starling.core.starling_internal;
+ import starling.events.Event;
+ import starling.events.EventDispatcher;
+
+ /** The Juggler takes objects that implement IAnimatable (like Tweens) and executes them.
+ *
+ *
A juggler is a simple object. It does no more than saving a list of objects implementing
+ * "IAnimatable" and advancing their time if it is told to do so (by calling its own
+ * "advanceTime"-method). When an animation is completed, it throws it away.
+ *
+ *
There is a default juggler available at the Starling class:
+ *
+ *
+ * var juggler:Juggler = Starling.juggler;
+ *
+ *
+ *
You can create juggler objects yourself, just as well. That way, you can group
+ * your game into logical components that handle their animations independently. All you have
+ * to do is call the "advanceTime" method on your custom juggler once per frame.
+ *
+ *
Another handy feature of the juggler is the "delayCall"-method. Use it to
+ * execute a function at a later time. Different to conventional approaches, the method
+ * will only be called when the juggler is advanced, giving you perfect control over the
+ * call.
+ *
+ * @see Tween
+ * @see DelayedCall
+ */
+ public class Juggler implements IAnimatable
+ {
+ private var _objects:Vector.;
+ private var _objectIDs:Dictionary;
+ private var _elapsedTime:Number;
+ private var _timeScale:Number;
+
+ private static var sCurrentObjectID:uint;
+
+ /** Create an empty juggler. */
+ public function Juggler()
+ {
+ _elapsedTime = 0;
+ _timeScale = 1.0;
+ _objects = new [];
+ _objectIDs = new Dictionary(true);
+ }
+
+ /** Adds an object to the juggler.
+ *
+ * @return Unique numeric identifier for the animation. This identifier may be used
+ * to remove the object via removeByID().
+ */
+ public function add(object:IAnimatable):uint
+ {
+ return addWithID(object, getNextID());
+ }
+
+ private function addWithID(object:IAnimatable, objectID:uint):uint
+ {
+ if (object && !(object in _objectIDs))
+ {
+ var dispatcher:EventDispatcher = object as EventDispatcher;
+ if (dispatcher) dispatcher.addEventListener(Event.REMOVE_FROM_JUGGLER, onRemove);
+
+ _objects[_objects.length] = object;
+ _objectIDs[object] = objectID;
+
+ return objectID;
+ }
+ else return 0;
+ }
+
+ /** Determines if an object has been added to the juggler. */
+ public function contains(object:IAnimatable):Boolean
+ {
+ return object in _objectIDs;
+ }
+
+ /** Removes an object from the juggler.
+ *
+ * @return The (now meaningless) unique numeric identifier for the animation, or zero
+ * if the object was not found.
+ */
+ public function remove(object:IAnimatable):uint
+ {
+ var objectID:uint = 0;
+
+ if (object && object in _objectIDs)
+ {
+ var dispatcher:EventDispatcher = object as EventDispatcher;
+ if (dispatcher) dispatcher.removeEventListener(Event.REMOVE_FROM_JUGGLER, onRemove);
+
+ var index:int = _objects.indexOf(object);
+ _objects[index] = null;
+
+ objectID = _objectIDs[object];
+ delete _objectIDs[object];
+ }
+
+ return objectID;
+ }
+
+ /** Removes an object from the juggler, identified by the unique numeric identifier you
+ * received when adding it.
+ *
+ *
It's not uncommon that an animatable object is added to a juggler repeatedly,
+ * e.g. when using an object-pool. Thus, when using the remove method,
+ * you might accidentally remove an object that has changed its context. By using
+ * removeByID instead, you can be sure to avoid that, since the objectID
+ * will always be unique.
+ *
+ * @return if successful, the passed objectID; if the object was not found, zero.
+ */
+ public function removeByID(objectID:uint):uint
+ {
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var object:IAnimatable = _objects[i];
+
+ if (_objectIDs[object] == objectID)
+ {
+ remove(object);
+ return objectID;
+ }
+ }
+
+ return 0;
+ }
+
+ /** Removes all tweens with a certain target. */
+ public function removeTweens(target:Object):void
+ {
+ if (target == null) return;
+
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var tween:Tween = _objects[i] as Tween;
+ if (tween && tween.target == target)
+ {
+ tween.removeEventListener(Event.REMOVE_FROM_JUGGLER, onRemove);
+ _objects[i] = null;
+ delete _objectIDs[tween];
+ }
+ }
+ }
+
+ /** Removes all delayed and repeated calls with a certain callback. */
+ public function removeDelayedCalls(callback:Function):void
+ {
+ if (callback == null) return;
+
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var delayedCall:DelayedCall = _objects[i] as DelayedCall;
+ if (delayedCall && delayedCall.callback == callback)
+ {
+ delayedCall.removeEventListener(Event.REMOVE_FROM_JUGGLER, onRemove);
+ _objects[i] = null;
+ delete _objectIDs[tween];
+ }
+ }
+ }
+
+ /** Figures out if the juggler contains one or more tweens with a certain target. */
+ public function containsTweens(target:Object):Boolean
+ {
+ if (target)
+ {
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var tween:Tween = _objects[i] as Tween;
+ if (tween && tween.target == target) return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Figures out if the juggler contains one or more delayed calls with a certain callback. */
+ public function containsDelayedCalls(callback:Function):Boolean
+ {
+ if (callback != null)
+ {
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var delayedCall:DelayedCall = _objects[i] as DelayedCall;
+ if (delayedCall && delayedCall.callback == callback) return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Removes all objects at once. */
+ public function purge():void
+ {
+ // the object vector is not purged right away, because if this method is called
+ // from an 'advanceTime' call, this would make the loop crash. Instead, the
+ // vector is filled with 'null' values. They will be cleaned up on the next call
+ // to 'advanceTime'.
+
+ for (var i:int=_objects.length-1; i>=0; --i)
+ {
+ var object:IAnimatable = _objects[i];
+ var dispatcher:EventDispatcher = object as EventDispatcher;
+ if (dispatcher) dispatcher.removeEventListener(Event.REMOVE_FROM_JUGGLER, onRemove);
+ _objects[i] = null;
+ delete _objectIDs[object];
+ }
+ }
+
+ /** Delays the execution of a function until delay seconds have passed.
+ * This method provides a convenient alternative for creating and adding a DelayedCall
+ * manually.
+ *
+ * @return Unique numeric identifier for the delayed call. This identifier may be used
+ * to remove the object via removeByID().
+ */
+ public function delayCall(call:Function, delay:Number, ...args):uint
+ {
+ if (call == null) throw new ArgumentError("call must not be null");
+
+ var delayedCall:DelayedCall = DelayedCall.starling_internal::fromPool(call, delay, args);
+ delayedCall.addEventListener(Event.REMOVE_FROM_JUGGLER, onPooledDelayedCallComplete);
+ return add(delayedCall);
+ }
+
+ /** Runs a function at a specified interval (in seconds). A 'repeatCount' of zero
+ * means that it runs indefinitely.
+ *
+ * @return Unique numeric identifier for the delayed call. This identifier may be used
+ * to remove the object via removeByID().
+ */
+ public function repeatCall(call:Function, interval:Number, repeatCount:int=0, ...args):uint
+ {
+ if (call == null) throw new ArgumentError("call must not be null");
+
+ var delayedCall:DelayedCall = DelayedCall.starling_internal::fromPool(call, interval, args);
+ delayedCall.repeatCount = repeatCount;
+ delayedCall.addEventListener(Event.REMOVE_FROM_JUGGLER, onPooledDelayedCallComplete);
+ return add(delayedCall);
+ }
+
+ private function onPooledDelayedCallComplete(event:Event):void
+ {
+ DelayedCall.starling_internal::toPool(event.target as DelayedCall);
+ }
+
+ /** Utilizes a tween to animate the target object over time seconds. Internally,
+ * this method uses a tween instance (taken from an object pool) that is added to the
+ * juggler right away. This method provides a convenient alternative for creating
+ * and adding a tween manually.
+ *
+ *
Fill 'properties' with key-value pairs that describe both the
+ * tween and the animation target. Here is an example:
To cancel the tween, call 'Juggler.removeTweens' with the same target, or pass
+ * the returned 'IAnimatable' instance to 'Juggler.remove()'. Do not use the returned
+ * IAnimatable otherwise; it is taken from a pool and will be reused.
+ *
+ *
Note that some property types may be animated in a special way:
+ *
+ *
If the property contains the string color or Color,
+ * it will be treated as an unsigned integer with a color value
+ * (e.g. 0xff0000 for red). Each color channel will be animated
+ * individually.
+ *
The same happens if you append the string #rgb to the name.
+ *
If you append #rad, the property is treated as an angle in radians,
+ * making sure it always uses the shortest possible arc for the rotation.
+ *
The string #deg does the same for angles in degrees.
+ *
+ */
+ public function tween(target:Object, time:Number, properties:Object):uint
+ {
+ if (target == null) throw new ArgumentError("target must not be null");
+
+ var tween:Tween = Tween.starling_internal::fromPool(target, time);
+
+ for (var property:String in properties)
+ {
+ var value:Object = properties[property];
+
+ if (tween.hasOwnProperty(property))
+ tween[property] = value;
+ else if (target.hasOwnProperty(Tween.getPropertyName(property)))
+ tween.animate(property, value as Number);
+ else
+ throw new ArgumentError("Invalid property: " + property);
+ }
+
+ tween.addEventListener(Event.REMOVE_FROM_JUGGLER, onPooledTweenComplete);
+ return add(tween);
+ }
+
+ private function onPooledTweenComplete(event:Event):void
+ {
+ Tween.starling_internal::toPool(event.target as Tween);
+ }
+
+ /** Advances all objects by a certain time (in seconds). */
+ public function advanceTime(time:Number):void
+ {
+ var numObjects:int = _objects.length;
+ var currentIndex:int = 0;
+ var i:int;
+
+ time *= _timeScale;
+ if (numObjects == 0 || time == 0) return;
+ _elapsedTime += time;
+
+ // there is a high probability that the "advanceTime" function modifies the list
+ // of animatables. we must not process new objects right now (they will be processed
+ // in the next frame), and we need to clean up any empty slots in the list.
+
+ for (i=0; i { return _objects; }
+ }
+}
diff --git a/mobile_version/src/starling/animation/Transitions.as b/mobile_version/src/starling/animation/Transitions.as
new file mode 100644
index 00000000..de708b61
--- /dev/null
+++ b/mobile_version/src/starling/animation/Transitions.as
@@ -0,0 +1,233 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+//
+// easing functions thankfully taken from http://dojotoolkit.org
+// and http://www.robertpenner.com/easing
+//
+
+package starling.animation
+{
+ import flash.utils.Dictionary;
+
+ import starling.errors.AbstractClassError;
+
+ /** The Transitions class contains static methods that define easing functions.
+ * Those functions are used by the Tween class to execute animations.
+ *
+ *
Here is a visual representation of the available transitions:
+ *
+ *
+ *
You can define your own transitions through the "registerTransition" function. A
+ * transition function must have the following signature, where ratio is
+ * in the range 0-1:
+ *
+ *
function myTransition(ratio:Number):Number
+ */
+ public class Transitions
+ {
+ public static const LINEAR:String = "linear";
+ public static const EASE_IN:String = "easeIn";
+ public static const EASE_OUT:String = "easeOut";
+ public static const EASE_IN_OUT:String = "easeInOut";
+ public static const EASE_OUT_IN:String = "easeOutIn";
+ public static const EASE_IN_BACK:String = "easeInBack";
+ public static const EASE_OUT_BACK:String = "easeOutBack";
+ public static const EASE_IN_OUT_BACK:String = "easeInOutBack";
+ public static const EASE_OUT_IN_BACK:String = "easeOutInBack";
+ public static const EASE_IN_ELASTIC:String = "easeInElastic";
+ public static const EASE_OUT_ELASTIC:String = "easeOutElastic";
+ public static const EASE_IN_OUT_ELASTIC:String = "easeInOutElastic";
+ public static const EASE_OUT_IN_ELASTIC:String = "easeOutInElastic";
+ public static const EASE_IN_BOUNCE:String = "easeInBounce";
+ public static const EASE_OUT_BOUNCE:String = "easeOutBounce";
+ public static const EASE_IN_OUT_BOUNCE:String = "easeInOutBounce";
+ public static const EASE_OUT_IN_BOUNCE:String = "easeOutInBounce";
+
+ private static var sTransitions:Dictionary;
+
+ /** @private */
+ public function Transitions() { throw new AbstractClassError(); }
+
+ /** Returns the transition function that was registered under a certain name. */
+ public static function getTransition(name:String):Function
+ {
+ if (sTransitions == null) registerDefaults();
+ return sTransitions[name];
+ }
+
+ /** Registers a new transition function under a certain name. */
+ public static function register(name:String, func:Function):void
+ {
+ if (sTransitions == null) registerDefaults();
+ sTransitions[name] = func;
+ }
+
+ private static function registerDefaults():void
+ {
+ sTransitions = new Dictionary();
+
+ register(LINEAR, linear);
+ register(EASE_IN, easeIn);
+ register(EASE_OUT, easeOut);
+ register(EASE_IN_OUT, easeInOut);
+ register(EASE_OUT_IN, easeOutIn);
+ register(EASE_IN_BACK, easeInBack);
+ register(EASE_OUT_BACK, easeOutBack);
+ register(EASE_IN_OUT_BACK, easeInOutBack);
+ register(EASE_OUT_IN_BACK, easeOutInBack);
+ register(EASE_IN_ELASTIC, easeInElastic);
+ register(EASE_OUT_ELASTIC, easeOutElastic);
+ register(EASE_IN_OUT_ELASTIC, easeInOutElastic);
+ register(EASE_OUT_IN_ELASTIC, easeOutInElastic);
+ register(EASE_IN_BOUNCE, easeInBounce);
+ register(EASE_OUT_BOUNCE, easeOutBounce);
+ register(EASE_IN_OUT_BOUNCE, easeInOutBounce);
+ register(EASE_OUT_IN_BOUNCE, easeOutInBounce);
+ }
+
+ // transition functions
+
+ protected static function linear(ratio:Number):Number
+ {
+ return ratio;
+ }
+
+ protected static function easeIn(ratio:Number):Number
+ {
+ return ratio * ratio * ratio;
+ }
+
+ protected static function easeOut(ratio:Number):Number
+ {
+ var invRatio:Number = ratio - 1.0;
+ return invRatio * invRatio * invRatio + 1;
+ }
+
+ protected static function easeInOut(ratio:Number):Number
+ {
+ return easeCombined(easeIn, easeOut, ratio);
+ }
+
+ protected static function easeOutIn(ratio:Number):Number
+ {
+ return easeCombined(easeOut, easeIn, ratio);
+ }
+
+ protected static function easeInBack(ratio:Number):Number
+ {
+ var s:Number = 1.70158;
+ return Math.pow(ratio, 2) * ((s + 1.0)*ratio - s);
+ }
+
+ protected static function easeOutBack(ratio:Number):Number
+ {
+ var invRatio:Number = ratio - 1.0;
+ var s:Number = 1.70158;
+ return Math.pow(invRatio, 2) * ((s + 1.0)*invRatio + s) + 1.0;
+ }
+
+ protected static function easeInOutBack(ratio:Number):Number
+ {
+ return easeCombined(easeInBack, easeOutBack, ratio);
+ }
+
+ protected static function easeOutInBack(ratio:Number):Number
+ {
+ return easeCombined(easeOutBack, easeInBack, ratio);
+ }
+
+ protected static function easeInElastic(ratio:Number):Number
+ {
+ if (ratio == 0 || ratio == 1) return ratio;
+ else
+ {
+ var p:Number = 0.3;
+ var s:Number = p/4.0;
+ var invRatio:Number = ratio - 1;
+ return -1.0 * Math.pow(2.0, 10.0*invRatio) * Math.sin((invRatio-s)*(2.0*Math.PI)/p);
+ }
+ }
+
+ protected static function easeOutElastic(ratio:Number):Number
+ {
+ if (ratio == 0 || ratio == 1) return ratio;
+ else
+ {
+ var p:Number = 0.3;
+ var s:Number = p/4.0;
+ return Math.pow(2.0, -10.0*ratio) * Math.sin((ratio-s)*(2.0*Math.PI)/p) + 1;
+ }
+ }
+
+ protected static function easeInOutElastic(ratio:Number):Number
+ {
+ return easeCombined(easeInElastic, easeOutElastic, ratio);
+ }
+
+ protected static function easeOutInElastic(ratio:Number):Number
+ {
+ return easeCombined(easeOutElastic, easeInElastic, ratio);
+ }
+
+ protected static function easeInBounce(ratio:Number):Number
+ {
+ return 1.0 - easeOutBounce(1.0 - ratio);
+ }
+
+ protected static function easeOutBounce(ratio:Number):Number
+ {
+ var s:Number = 7.5625;
+ var p:Number = 2.75;
+ var l:Number;
+ if (ratio < (1.0/p))
+ {
+ l = s * Math.pow(ratio, 2);
+ }
+ else
+ {
+ if (ratio < (2.0/p))
+ {
+ ratio -= 1.5/p;
+ l = s * Math.pow(ratio, 2) + 0.75;
+ }
+ else
+ {
+ if (ratio < 2.5/p)
+ {
+ ratio -= 2.25/p;
+ l = s * Math.pow(ratio, 2) + 0.9375;
+ }
+ else
+ {
+ ratio -= 2.625/p;
+ l = s * Math.pow(ratio, 2) + 0.984375;
+ }
+ }
+ }
+ return l;
+ }
+
+ protected static function easeInOutBounce(ratio:Number):Number
+ {
+ return easeCombined(easeInBounce, easeOutBounce, ratio);
+ }
+
+ protected static function easeOutInBounce(ratio:Number):Number
+ {
+ return easeCombined(easeOutBounce, easeInBounce, ratio);
+ }
+
+ protected static function easeCombined(startFunc:Function, endFunc:Function, ratio:Number):Number
+ {
+ if (ratio < 0.5) return 0.5 * startFunc(ratio*2.0);
+ else return 0.5 * endFunc((ratio-0.5)*2.0) + 0.5;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/animation/Tween.as b/mobile_version/src/starling/animation/Tween.as
new file mode 100644
index 00000000..561bd944
--- /dev/null
+++ b/mobile_version/src/starling/animation/Tween.as
@@ -0,0 +1,451 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+
+package starling.animation
+{
+ import starling.core.starling_internal;
+ import starling.events.Event;
+ import starling.events.EventDispatcher;
+ import starling.utils.Color;
+
+ /** A Tween animates numeric properties of objects. It uses different transition functions
+ * to give the animations various styles.
+ *
+ *
The primary use of this class is to do standard animations like movement, fading,
+ * rotation, etc. But there are no limits on what to animate; as long as the property you want
+ * to animate is numeric (int, uint, Number), the tween can handle it. For a list
+ * of available Transition types, look at the "Transitions" class.
+ *
+ *
Here is an example of a tween that moves an object to the right, rotates it, and
+ * fades it out:
Note that the object is added to a juggler at the end of this sample. That's because a
+ * tween will only be executed if its "advanceTime" method is executed regularly - the
+ * juggler will do that for you, and will remove the tween when it is finished.
+ *
+ * @see Juggler
+ * @see Transitions
+ */
+ public class Tween extends EventDispatcher implements IAnimatable
+ {
+ private static const HINT_MARKER:String = '#';
+
+ private var _target:Object;
+ private var _transitionFunc:Function;
+ private var _transitionName:String;
+
+ private var _properties:Vector.;
+ private var _startValues:Vector.;
+ private var _endValues:Vector.;
+ private var _updateFuncs:Vector.;
+
+ private var _onStart:Function;
+ private var _onUpdate:Function;
+ private var _onRepeat:Function;
+ private var _onComplete:Function;
+
+ private var _onStartArgs:Array;
+ private var _onUpdateArgs:Array;
+ private var _onRepeatArgs:Array;
+ private var _onCompleteArgs:Array;
+
+ private var _totalTime:Number;
+ private var _currentTime:Number;
+ private var _progress:Number;
+ private var _delay:Number;
+ private var _roundToInt:Boolean;
+ private var _nextTween:Tween;
+ private var _repeatCount:int;
+ private var _repeatDelay:Number;
+ private var _reverse:Boolean;
+ private var _currentCycle:int;
+
+ /** Creates a tween with a target, duration (in seconds) and a transition function.
+ * @param target the object that you want to animate
+ * @param time the duration of the Tween (in seconds)
+ * @param transition can be either a String (e.g. one of the constants defined in the
+ * Transitions class) or a function. Look up the 'Transitions' class for a
+ * documentation about the required function signature. */
+ public function Tween(target:Object, time:Number, transition:Object="linear")
+ {
+ reset(target, time, transition);
+ }
+
+ /** Resets the tween to its default values. Useful for pooling tweens. */
+ public function reset(target:Object, time:Number, transition:Object="linear"):Tween
+ {
+ _target = target;
+ _currentTime = 0.0;
+ _totalTime = Math.max(0.0001, time);
+ _progress = 0.0;
+ _delay = _repeatDelay = 0.0;
+ _onStart = _onUpdate = _onRepeat = _onComplete = null;
+ _onStartArgs = _onUpdateArgs = _onRepeatArgs = _onCompleteArgs = null;
+ _roundToInt = _reverse = false;
+ _repeatCount = 1;
+ _currentCycle = -1;
+ _nextTween = null;
+
+ if (transition is String)
+ this.transition = transition as String;
+ else if (transition is Function)
+ this.transitionFunc = transition as Function;
+ else
+ throw new ArgumentError("Transition must be either a string or a function");
+
+ if (_properties) _properties.length = 0; else _properties = new [];
+ if (_startValues) _startValues.length = 0; else _startValues = new [];
+ if (_endValues) _endValues.length = 0; else _endValues = new [];
+ if (_updateFuncs) _updateFuncs.length = 0; else _updateFuncs = new [];
+
+ return this;
+ }
+
+ /** Animates the property of the target to a certain value. You can call this method
+ * multiple times on one tween.
+ *
+ *
Some property types are handled in a special way:
+ *
+ *
If the property contains the string color or Color,
+ * it will be treated as an unsigned integer with a color value
+ * (e.g. 0xff0000 for red). Each color channel will be animated
+ * individually.
+ *
The same happens if you append the string #rgb to the name.
+ *
If you append #rad, the property is treated as an angle in radians,
+ * making sure it always uses the shortest possible arc for the rotation.
+ *
The string #deg does the same for angles in degrees.
+ *
+ */
+ public function animate(property:String, endValue:Number):void
+ {
+ if (_target == null) return; // tweening null just does nothing.
+
+ var pos:int = _properties.length;
+ var updateFunc:Function = getUpdateFuncFromProperty(property);
+
+ _properties[pos] = getPropertyName(property);
+ _startValues[pos] = Number.NaN;
+ _endValues[pos] = endValue;
+ _updateFuncs[pos] = updateFunc;
+ }
+
+ /** Animates the 'scaleX' and 'scaleY' properties of an object simultaneously. */
+ public function scaleTo(factor:Number):void
+ {
+ animate("scaleX", factor);
+ animate("scaleY", factor);
+ }
+
+ /** Animates the 'x' and 'y' properties of an object simultaneously. */
+ public function moveTo(x:Number, y:Number):void
+ {
+ animate("x", x);
+ animate("y", y);
+ }
+
+ /** Animates the 'alpha' property of an object to a certain target value. */
+ public function fadeTo(alpha:Number):void
+ {
+ animate("alpha", alpha);
+ }
+
+ /** Animates the 'rotation' property of an object to a certain target value, using the
+ * smallest possible arc. 'type' may be either 'rad' or 'deg', depending on the unit of
+ * measurement. */
+ public function rotateTo(angle:Number, type:String="rad"):void
+ {
+ animate("rotation#" + type, angle);
+ }
+
+ /** @inheritDoc */
+ public function advanceTime(time:Number):void
+ {
+ if (time == 0 || (_repeatCount == 1 && _currentTime == _totalTime)) return;
+
+ var i:int;
+ var previousTime:Number = _currentTime;
+ var restTime:Number = _totalTime - _currentTime;
+ var carryOverTime:Number = time > restTime ? time - restTime : 0.0;
+
+ _currentTime += time;
+
+ if (_currentTime <= 0)
+ return; // the delay is not over yet
+ else if (_currentTime > _totalTime)
+ _currentTime = _totalTime;
+
+ if (_currentCycle < 0 && previousTime <= 0 && _currentTime > 0)
+ {
+ _currentCycle++;
+ if (_onStart != null) _onStart.apply(this, _onStartArgs);
+ }
+
+ var ratio:Number = _currentTime / _totalTime;
+ var reversed:Boolean = _reverse && (_currentCycle % 2 == 1);
+ var numProperties:int = _startValues.length;
+ _progress = reversed ? _transitionFunc(1.0 - ratio) : _transitionFunc(ratio);
+
+ for (i=0; i= _totalTime)
+ {
+ if (_repeatCount == 0 || _repeatCount > 1)
+ {
+ _currentTime = -_repeatDelay;
+ _currentCycle++;
+ if (_repeatCount > 1) _repeatCount--;
+ if (_onRepeat != null) _onRepeat.apply(this, _onRepeatArgs);
+ }
+ else
+ {
+ // save callback & args: they might be changed through an event listener
+ var onComplete:Function = _onComplete;
+ var onCompleteArgs:Array = _onCompleteArgs;
+
+ // in the 'onComplete' callback, people might want to call "tween.reset" and
+ // add it to another juggler; so this event has to be dispatched *before*
+ // executing 'onComplete'.
+ dispatchEventWith(Event.REMOVE_FROM_JUGGLER);
+ if (onComplete != null) onComplete.apply(this, onCompleteArgs);
+ if (_currentTime == 0) carryOverTime = 0; // tween was reset
+ }
+ }
+
+ if (carryOverTime)
+ advanceTime(carryOverTime);
+ }
+
+ // animation hints
+
+ private function getUpdateFuncFromProperty(property:String):Function
+ {
+ var updateFunc:Function;
+ var hint:String = getPropertyHint(property);
+
+ switch (hint)
+ {
+ case null: updateFunc = updateStandard; break;
+ case "rgb": updateFunc = updateRgb; break;
+ case "rad": updateFunc = updateRad; break;
+ case "deg": updateFunc = updateDeg; break;
+ default:
+ trace("[Starling] Ignoring unknown property hint:", hint);
+ updateFunc = updateStandard;
+ }
+
+ return updateFunc;
+ }
+
+ /** @private */
+ internal static function getPropertyHint(property:String):String
+ {
+ // colorization is special; it does not require a hint marker, just the word 'color'.
+ if (property.indexOf("color") != -1 || property.indexOf("Color") != -1)
+ return "rgb";
+
+ var hintMarkerIndex:int = property.indexOf(HINT_MARKER);
+ if (hintMarkerIndex != -1) return property.substr(hintMarkerIndex+1);
+ else return null;
+ }
+
+ /** @private */
+ internal static function getPropertyName(property:String):String
+ {
+ var hintMarkerIndex:int = property.indexOf(HINT_MARKER);
+ if (hintMarkerIndex != -1) return property.substring(0, hintMarkerIndex);
+ else return property;
+ }
+
+ private function updateStandard(property:String, startValue:Number, endValue:Number):void
+ {
+ var newValue:Number = startValue + _progress * (endValue - startValue);
+ if (_roundToInt) newValue = Math.round(newValue);
+ _target[property] = newValue;
+ }
+
+ private function updateRgb(property:String, startValue:Number, endValue:Number):void
+ {
+ _target[property] = Color.interpolate(uint(startValue), uint(endValue), _progress);
+ }
+
+ private function updateRad(property:String, startValue:Number, endValue:Number):void
+ {
+ updateAngle(Math.PI, property, startValue, endValue);
+ }
+
+ private function updateDeg(property:String, startValue:Number, endValue:Number):void
+ {
+ updateAngle(180, property, startValue, endValue);
+ }
+
+ private function updateAngle(pi:Number, property:String, startValue:Number, endValue:Number):void
+ {
+ while (Math.abs(endValue - startValue) > pi)
+ {
+ if (startValue < endValue) endValue -= 2.0 * pi;
+ else endValue += 2.0 * pi;
+ }
+
+ updateStandard(property, startValue, endValue);
+ }
+
+ /** The end value a certain property is animated to. Throws an ArgumentError if the
+ * property is not being animated. */
+ public function getEndValue(property:String):Number
+ {
+ var index:int = _properties.indexOf(property);
+ if (index == -1) throw new ArgumentError("The property '" + property + "' is not animated");
+ else return _endValues[index] as Number;
+ }
+
+ /** Indicates if the tween is finished. */
+ public function get isComplete():Boolean
+ {
+ return _currentTime >= _totalTime && _repeatCount == 1;
+ }
+
+ /** The target object that is animated. */
+ public function get target():Object { return _target; }
+
+ /** The transition method used for the animation. @see Transitions */
+ public function get transition():String { return _transitionName; }
+ public function set transition(value:String):void
+ {
+ _transitionName = value;
+ _transitionFunc = Transitions.getTransition(value);
+
+ if (_transitionFunc == null)
+ throw new ArgumentError("Invalid transiton: " + value);
+ }
+
+ /** The actual transition function used for the animation. */
+ public function get transitionFunc():Function { return _transitionFunc; }
+ public function set transitionFunc(value:Function):void
+ {
+ _transitionName = "custom";
+ _transitionFunc = value;
+ }
+
+ /** The total time the tween will take per repetition (in seconds). */
+ public function get totalTime():Number { return _totalTime; }
+
+ /** The time that has passed since the tween was created (in seconds). */
+ public function get currentTime():Number { return _currentTime; }
+
+ /** The current progress between 0 and 1, as calculated by the transition function. */
+ public function get progress():Number { return _progress; }
+
+ /** The delay before the tween is started (in seconds). @default 0 */
+ public function get delay():Number { return _delay; }
+ public function set delay(value:Number):void
+ {
+ _currentTime = _currentTime + _delay - value;
+ _delay = value;
+ }
+
+ /** The number of times the tween will be executed.
+ * Set to '0' to tween indefinitely. @default 1 */
+ public function get repeatCount():int { return _repeatCount; }
+ public function set repeatCount(value:int):void { _repeatCount = value; }
+
+ /** The amount of time to wait between repeat cycles (in seconds). @default 0 */
+ public function get repeatDelay():Number { return _repeatDelay; }
+ public function set repeatDelay(value:Number):void { _repeatDelay = value; }
+
+ /** Indicates if the tween should be reversed when it is repeating. If enabled,
+ * every second repetition will be reversed. @default false */
+ public function get reverse():Boolean { return _reverse; }
+ public function set reverse(value:Boolean):void { _reverse = value; }
+
+ /** Indicates if the numeric values should be cast to Integers. @default false */
+ public function get roundToInt():Boolean { return _roundToInt; }
+ public function set roundToInt(value:Boolean):void { _roundToInt = value; }
+
+ /** A function that will be called when the tween starts (after a possible delay). */
+ public function get onStart():Function { return _onStart; }
+ public function set onStart(value:Function):void { _onStart = value; }
+
+ /** A function that will be called each time the tween is advanced. */
+ public function get onUpdate():Function { return _onUpdate; }
+ public function set onUpdate(value:Function):void { _onUpdate = value; }
+
+ /** A function that will be called each time the tween finishes one repetition
+ * (except the last, which will trigger 'onComplete'). */
+ public function get onRepeat():Function { return _onRepeat; }
+ public function set onRepeat(value:Function):void { _onRepeat = value; }
+
+ /** A function that will be called when the tween is complete. */
+ public function get onComplete():Function { return _onComplete; }
+ public function set onComplete(value:Function):void { _onComplete = value; }
+
+ /** The arguments that will be passed to the 'onStart' function. */
+ public function get onStartArgs():Array { return _onStartArgs; }
+ public function set onStartArgs(value:Array):void { _onStartArgs = value; }
+
+ /** The arguments that will be passed to the 'onUpdate' function. */
+ public function get onUpdateArgs():Array { return _onUpdateArgs; }
+ public function set onUpdateArgs(value:Array):void { _onUpdateArgs = value; }
+
+ /** The arguments that will be passed to the 'onRepeat' function. */
+ public function get onRepeatArgs():Array { return _onRepeatArgs; }
+ public function set onRepeatArgs(value:Array):void { _onRepeatArgs = value; }
+
+ /** The arguments that will be passed to the 'onComplete' function. */
+ public function get onCompleteArgs():Array { return _onCompleteArgs; }
+ public function set onCompleteArgs(value:Array):void { _onCompleteArgs = value; }
+
+ /** Another tween that will be started (i.e. added to the same juggler) as soon as
+ * this tween is completed. */
+ public function get nextTween():Tween { return _nextTween; }
+ public function set nextTween(value:Tween):void { _nextTween = value; }
+
+ // tween pooling
+
+ private static var sTweenPool:Vector. = new [];
+
+ /** @private */
+ starling_internal static function fromPool(target:Object, time:Number,
+ transition:Object="linear"):Tween
+ {
+ if (sTweenPool.length) return sTweenPool.pop().reset(target, time, transition);
+ else return new Tween(target, time, transition);
+ }
+
+ /** @private */
+ starling_internal static function toPool(tween:Tween):void
+ {
+ // reset any object-references, to make sure we don't prevent any garbage collection
+ tween._onStart = tween._onUpdate = tween._onRepeat = tween._onComplete = null;
+ tween._onStartArgs = tween._onUpdateArgs = tween._onRepeatArgs = tween._onCompleteArgs = null;
+ tween._target = null;
+ tween._transitionFunc = null;
+ tween.removeEventListeners();
+ sTweenPool.push(tween);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/AssetFactory.as b/mobile_version/src/starling/assets/AssetFactory.as
new file mode 100644
index 00000000..01cfeecc
--- /dev/null
+++ b/mobile_version/src/starling/assets/AssetFactory.as
@@ -0,0 +1,122 @@
+package starling.assets
+{
+ import flash.system.Capabilities;
+ import flash.utils.ByteArray;
+ import flash.utils.getQualifiedClassName;
+
+ import starling.errors.AbstractClassError;
+
+ /** An AssetFactory is responsible for creating a concrete instance of an asset.
+ *
+ *
The AssetManager contains a list of AssetFactories, registered via 'registerFactory'.
+ * When the asset queue is processed, each factory (sorted by priority) will be asked if it
+ * can handle a certain AssetReference (via the 'canHandle') method. If it can, the 'create'
+ * method will be called, which is responsible for creating at least one asset.
+ *
+ *
By extending 'AssetFactory' and registering your class at the AssetManager, you can
+ * customize how assets are being created and even add new types of assets.
+ */
+ public class AssetFactory
+ {
+ private var _priority:int;
+ private var _mimeTypes:Vector.;
+ private var _extensions:Vector.;
+
+ /** Creates a new instance. */
+ public function AssetFactory()
+ {
+ if (Capabilities.isDebugger &&
+ getQualifiedClassName(this) == "starling.assets::AssetFactory")
+ {
+ throw new AbstractClassError();
+ }
+
+ _mimeTypes = new [];
+ _extensions = new [];
+ }
+
+ /** Returns 'true' if this factory can handle the given reference. The default
+ * implementation checks if extension and/or mime type of the reference match those
+ * of the factory. */
+ public function canHandle(reference:AssetReference):Boolean
+ {
+ var mimeType:String = reference.mimeType;
+ var extension:String = reference.extension;
+
+ return reference.data is ByteArray && (
+ (mimeType && _mimeTypes.indexOf(reference.mimeType.toLowerCase()) != -1) ||
+ (extension && _extensions.indexOf(reference.extension.toLowerCase()) != -1));
+ }
+
+ /** This method will only be called if 'canHandle' returned 'true' for the given reference.
+ * It's responsible for creating at least one concrete asset and passing it to 'onComplete'.
+ *
+ * @param reference The asset to be created. If a local or remote URL is referenced,
+ * it will already have been loaded, and 'data' will contain a ByteArray.
+ * @param helper Contains useful utility methods to be used by the factory. Look
+ * at the class documentation for more information.
+ * @param onComplete To be called when loading is successful. 'type' parameter is optional.
+ *
+ * @param onError To be called when creation fails for some reason. Do not call
+ * 'onComplete' when that happens.
function(error:String):void
+ */
+ public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ // to be implemented by subclasses
+ }
+
+ /** Add one or more mime types that identify the supported data types. Used by
+ * 'canHandle' to figure out if the factory is suitable for an asset reference. */
+ public function addMimeTypes(...args):void
+ {
+ for each (var mimeType:String in args)
+ {
+ mimeType = mimeType.toLowerCase();
+
+ if (_mimeTypes.indexOf(mimeType) == -1)
+ _mimeTypes[_mimeTypes.length] = mimeType;
+ }
+ }
+
+ /** Add one or more file extensions (without leading dot) that identify the supported data
+ * types. Used by 'canHandle' to figure out if the factory is suitable for an asset
+ * reference. */
+ public function addExtensions(...args):void
+ {
+ for each (var extension:String in args)
+ {
+ extension = extension.toLowerCase();
+
+ if (_extensions.indexOf(extension) == -1)
+ _extensions[_extensions.length] = extension;
+ }
+ }
+
+ /** Returns the mime types this factory supports. */
+ public function getMimeTypes(out:Vector.=null):Vector.
+ {
+ out ||= new Vector.();
+
+ for (var i:int=0; i<_mimeTypes.length; ++i)
+ out[i] = _mimeTypes[i];
+
+ return out;
+ }
+
+ /** Returns the file extensions this factory supports. */
+ public function getExtensions(out:Vector.=null):Vector.
+ {
+ out ||= new Vector.();
+
+ for (var i:int=0; i<_extensions.length; ++i)
+ out[i] = _extensions[i];
+
+ return out;
+ }
+
+ /** @private */
+ internal function get priority():int { return _priority; }
+ internal function set priority(value:int):void { _priority = value; }
+ }
+}
diff --git a/mobile_version/src/starling/assets/AssetFactoryHelper.as b/mobile_version/src/starling/assets/AssetFactoryHelper.as
new file mode 100644
index 00000000..6c8b57ea
--- /dev/null
+++ b/mobile_version/src/starling/assets/AssetFactoryHelper.as
@@ -0,0 +1,124 @@
+package starling.assets
+{
+ import starling.utils.SystemUtil;
+
+ /** A helper class that's passed to an AssetFactory's "create" method. */
+ public class AssetFactoryHelper
+ {
+ private var _dataLoader:DataLoader;
+ private var _getNameFromUrlFunc:Function;
+ private var _getExtensionFromUrlFunc:Function;
+ private var _addPostProcessorFunc:Function;
+ private var _addAssetFunc:Function;
+ private var _onRestoreFunc:Function;
+ private var _logFunc:Function;
+
+ /** @private */
+ public function AssetFactoryHelper()
+ { }
+
+ /** Forwarded to the AssetManager's method with the same name. */
+ public function getNameFromUrl(url:String):String
+ {
+ if (_getNameFromUrlFunc != null) return _getNameFromUrlFunc(url);
+ else return "";
+ }
+
+ /** Forwarded to the AssetManager's method with the same name. */
+ public function getExtensionFromUrl(url:String):String
+ {
+ if (_getExtensionFromUrlFunc != null) return _getExtensionFromUrlFunc(url);
+ else return "";
+ }
+
+ /** Accesses a URL (local or remote) and passes the loaded ByteArray to the
+ * 'onComplete' callback - or executes 'onError' when the data can't be loaded.
+ *
+ * @param url a string containing an URL.
+ * @param onComplete function(data:ByteArray, mimeType:String):void;
+ * @param onError function(error:String):void;
+ */
+ public function loadDataFromUrl(url:String, onComplete:Function, onError:Function):void
+ {
+ if (_dataLoader) _dataLoader.load(url, onComplete, onError);
+ }
+
+ /** Adds a method to be called by the AssetManager when the queue has finished processing.
+ * Useful e.g. if assets depend on other assets (like an atlas XML depending on the atlas
+ * texture).
+ *
+ * @param processor function(manager:AssetManager):void;
+ * @param priority Processors with a higher priority will be called first.
+ * The default processor for texture atlases is called with a
+ * priority of '100', others with '0'.
+ */
+ public function addPostProcessor(processor:Function, priority:int=0):void
+ {
+ if (_addPostProcessorFunc != null) _addPostProcessorFunc(processor, priority);
+ }
+
+ /** Textures are required to call this method when they begin their restoration process
+ * after a context loss. */
+ public function onBeginRestore():void
+ {
+ if (_onRestoreFunc != null) _onRestoreFunc(false);
+ }
+
+ /** Textures are required to call this method when they have finished their restoration
+ * process after a context loss. */
+ public function onEndRestore():void
+ {
+ if (_onRestoreFunc != null) _onRestoreFunc(true);
+ }
+
+ /** Forwarded to the AssetManager's method with the same name. */
+ public function log(message:String):void
+ {
+ if (_logFunc != null) _logFunc(message);
+ }
+
+ /** Adds additional assets to the AssetManager. To be called when the factory
+ * creates more than one asset. */
+ public function addComplementaryAsset(name:String, asset:Object, type:String=null):void
+ {
+ if (_addAssetFunc != null) _addAssetFunc(name, asset, type);
+ }
+
+ /** Delay the execution of 'call' until it's allowed. (On mobile, the context
+ * may not be accessed while the application is in the background.)
+ */
+ public function executeWhenContextReady(call:Function, ...args):void
+ {
+ // On mobile, it is not allowed / endorsed to make stage3D calls while the app
+ // is in the background. Thus, we pause execution if that's the case.
+
+ if (SystemUtil.isDesktop) call.apply(this, args);
+ else
+ {
+ args.unshift(call);
+ SystemUtil.executeWhenApplicationIsActive.apply(this, args);
+ }
+ }
+
+ /** @private */
+ internal function set getNameFromUrlFunc(value:Function):void { _getNameFromUrlFunc = value; }
+
+ /** @private */
+ internal function set getExtensionFromUrlFunc(value:Function):void { _getExtensionFromUrlFunc = value; }
+
+ /** @private */
+ internal function set dataLoader(value:DataLoader):void { _dataLoader = value; }
+
+ /** @private */
+ internal function set logFunc(value:Function):void { _logFunc = value; }
+
+ /** @private */
+ internal function set addAssetFunc(value:Function):void { _addAssetFunc = value; }
+
+ /** @private */
+ internal function set onRestoreFunc(value:Function):void { _onRestoreFunc = value; }
+
+ /** @private */
+ internal function set addPostProcessorFunc(value:Function):void { _addPostProcessorFunc = value; }
+ }
+}
diff --git a/mobile_version/src/starling/assets/AssetManager.as b/mobile_version/src/starling/assets/AssetManager.as
new file mode 100644
index 00000000..44541910
--- /dev/null
+++ b/mobile_version/src/starling/assets/AssetManager.as
@@ -0,0 +1,1034 @@
+package starling.assets
+{
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+ import flash.media.SoundTransform;
+ import flash.net.URLRequest;
+ import flash.system.System;
+ import flash.utils.ByteArray;
+ import flash.utils.Dictionary;
+ import flash.utils.describeType;
+ import flash.utils.getQualifiedClassName;
+ import flash.utils.setTimeout;
+
+ import starling.core.Starling;
+ import starling.events.Event;
+ import starling.events.EventDispatcher;
+ import starling.text.BitmapFont;
+ import starling.textures.Texture;
+ import starling.textures.TextureAtlas;
+ import starling.textures.TextureOptions;
+ import starling.utils.MathUtil;
+ import starling.utils.execute;
+
+ /** Dispatched when all textures have been restored after a context loss. */
+ [Event(name="texturesRestored", type="starling.events.Event")]
+
+ /** The AssetManager handles loading and accessing a variety of asset types. You can
+ * add assets directly (via the 'add...' methods) or asynchronously via a queue. This allows
+ * you to deal with assets in a unified way, no matter if they are loaded from a file,
+ * directory, URL, or from an embedded object.
+ *
+ *
The class can deal with the following media types:
+ *
+ *
Textures (either from Bitmaps or ATF data)
+ *
Texture atlases
+ *
Bitmap Fonts
+ *
Sounds
+ *
XML data
+ *
JSON data
+ *
ByteArrays
+ *
other AssetManagers
+ *
+ *
+ *
+ *
For more information on how to add assets from different sources, read the documentation
+ * of the "enqueue()" method.
+ *
+ * Context Loss
+ *
+ *
When the stage3D context is lost, the AssetManager will automatically restore all
+ * loaded textures. To save memory, it will get them from their original sources. Since
+ * this is done asynchronously, your images might not reappear all at once, but during
+ * a time frame of several seconds. If you want, you can pause your game during that time;
+ * the AssetManager dispatches an "Event.TEXTURES_RESTORED" event when all textures have
+ * been restored.
+ *
+ * Error Handling
+ *
+ *
Loading of some assets may fail while the queue is being processed. In that case, the
+ * AssetManager will call the 'onError' callback that you can optional provide to the
+ * 'loadQueue' method. Queue processing will continue after an error, so it's always
+ * guaranteed that the 'onComplete' callback is executed, too.
+ *
+ * Texture Properties
+ *
+ *
When you enqueue a texture, its properties for "format", "scale", "mipMapping", and
+ * "repeat" will reflect the settings of the AssetManager at the time they were enqueued.
+ * This means that you can enqueue a bunch of textures, then change the settings and enqueue
+ * some more. Like this:
When you enqueue one or more AssetManagers to another one, the "loadQueue" method will
+ * load the assets of the "child" AssetManager, as well. Later, when accessing assets,
+ * the "parent" AssetManager will return the "child" assets as well - just like it returns,
+ * say, the SubTextures from a contained TextureAtlas.
+ *
+ *
The main advantage of grouping your assets like this is something else, though: it
+ * allows to remove (and dispose) a complete group of assets in one step. The example
+ * below loads the assets from two directories. When the contents of one of them are no
+ * longer needed, all its assets are removed together.
+ *
+ *
+ * var manager:AssetManager = new AssetManager();
+ * var appDir:File = File.applicationDirectory;
+ *
+ * var redAssets:AssetManager = new AssetManager();
+ * redAssets.enqueueSingle(appDir.resolvePath("textures/red/"));
+ *
+ * var greenAssets:AssetManager = new AssetManager();
+ * greenAssets.enqueueSingle(appDir.resolvePath("textures/green/"));
+ *
+ * manager.enqueueSingle(redAssets, "redAssets");
+ * manager.enqueueSingle(greenAssets, "greenAssets");
+ * manager.loadQueue(...); // loads both "red" and "green" assets
+ *
+ * // ... later, remove all "red" assets together
+ * manager.removeAssetManager("redAssets");
+ *
+ * Customization
+ *
+ *
You can customize how assets are created by extending the 'AssetFactory' class and
+ * registering an instance of your new class at the AssetManager via 'registerFactory'.
+ * Factories are probed by priority; any factory with a priority > 0 will be executed
+ * before the built-in factories.
+ *
+ *
An asset type is identified by a unique String. You can add your own asset types
+ * by creating a custom 'AssetFactory' and having it add the asset with custom string
+ * identifier.
+ *
+ *
By overriding the methods 'getNameFromUrl', 'getExtensionFromUrl', 'disposeAsset',
+ * and 'log', you can customize how assets are named and disposed, and you can forward
+ * any logging to an external logger. To customize the way data is loaded from URLs or
+ * files, you can assign a custom 'DataLoader' instance to the AssetManager.
+ *
+ * @see starling.assets.AssetFactory
+ * @see starling.assets.AssetType
+ * @see starling.assets.DataLoader
+ */
+ public class AssetManager extends EventDispatcher
+ {
+ private var _starling:Starling;
+ private var _assets:Dictionary;
+ private var _verbose:Boolean;
+ private var _numConnections:int;
+ private var _dataLoader:DataLoader;
+ private var _textureOptions:TextureOptions;
+ private var _queue:Vector.;
+ private var _registerBitmapFontsWithFontFace:Boolean;
+ private var _assetFactories:Vector.;
+ private var _numRestoredTextures:int;
+ private var _numLostTextures:int;
+
+ // Regex for name / extension extraction from URLs.
+ private static const NAME_REGEX:RegExp = /(([^?\/\\]+?)(?:\.([\w\-]+))?)(?:\?.*)?$/;
+
+ // fallback for unnamed assets
+ private static const NO_NAME:String = "unnamed";
+ private static var sNoNameCount:int = 0;
+
+ // helper objects
+ private static var sNames:Vector. = new [];
+
+ /** Create a new instance with the given scale factor. */
+ public function AssetManager(scaleFactor:Number=1)
+ {
+ _assets = new Dictionary();
+ _verbose = true;
+ _textureOptions = new TextureOptions(scaleFactor);
+ _queue = new [];
+ _numConnections = 3;
+ _dataLoader = new DataLoader();
+ _assetFactories = new [];
+
+ registerFactory(new BitmapTextureFactory());
+ registerFactory(new AtfTextureFactory());
+ registerFactory(new SoundFactory());
+ registerFactory(new JsonFactory());
+ registerFactory(new XmlFactory());
+ registerFactory(new ByteArrayFactory(), -100);
+ }
+
+ /** Disposes all assets and purges the queue.
+ *
+ *
Beware that all references to the assets will remain intact, even though the assets
+ * are no longer valid. Call 'purge' if you want to remove all resources and reuse
+ * the AssetManager later.
+ */
+ public function dispose():void
+ {
+ purgeQueue();
+
+ for each (var store:Dictionary in _assets)
+ for each (var asset:Object in store)
+ disposeAsset(asset);
+ }
+
+ /** Removes assets of all types (disposing them along the way), empties the queue and
+ * aborts any pending load operations. */
+ public function purge():void
+ {
+ log("Purging all assets, emptying queue");
+
+ purgeQueue();
+ dispose();
+
+ _assets = new Dictionary();
+ }
+
+ // queue processing
+
+ /** Enqueues one or more raw assets; they will only be available after successfully
+ * executing the "loadQueue" method. This method accepts a variety of different objects:
+ *
+ *
+ *
Strings or URLRequests containing an URL to a local or remote resource. Supported
+ * types: png, jpg, gif, atf, mp3, xml, fnt, json, binary.
+ *
Instances of the File class (AIR only) pointing to a directory or a file.
+ * Directories will be scanned recursively for all supported types.
+ *
Classes that contain static embedded assets.
+ *
If the file extension is not recognized, the data is analyzed to see if
+ * contains XML or JSON data. If it's neither, it is stored as ByteArray.
+ *
+ *
+ *
Suitable object names are extracted automatically: A file named "image.png" will be
+ * accessible under the name "image". When enqueuing embedded assets via a class,
+ * the variable name of the embedded object will be used as its name. An exception
+ * are texture atlases: they will have the same name as the actual texture they are
+ * referencing.
+ *
+ *
XMLs are made available via "getXml()"; this includes XMLs containing texture
+ * atlases or bitmap fonts, which are processed along the way. Bitmap fonts are also
+ * registered at the TextField class.
+ *
+ *
If you pass in JSON data, it will be parsed into an object and will be available via
+ * "getObject()".
+ */
+ public function enqueue(...assets):void
+ {
+ for each (var asset:Object in assets)
+ {
+ if (asset is Array)
+ {
+ enqueue.apply(this, asset);
+ }
+ else if (asset is Class)
+ {
+ var typeXml:XML = describeType(asset);
+ var childNode:XML;
+
+ if (_verbose)
+ log("Looking for static embedded assets in '" +
+ (typeXml.@name).split("::").pop() + "'");
+
+ for each (childNode in typeXml.constant.(@type == "Class"))
+ enqueueSingle(asset[childNode.@name], childNode.@name);
+
+ for each (childNode in typeXml.variable.(@type == "Class"))
+ enqueueSingle(asset[childNode.@name], childNode.@name);
+ }
+ else if (getQualifiedClassName(asset) == "flash.filesystem::File")
+ {
+ if (!asset["exists"])
+ {
+ log("File or directory not found: '" + asset["url"] + "'");
+ }
+ else if (!asset["isHidden"])
+ {
+ if (asset["isDirectory"])
+ enqueue.apply(this, asset["getDirectoryListing"]());
+ else
+ enqueueSingle(asset);
+ }
+ }
+ else if (asset is String || asset is URLRequest || asset is AssetManager)
+ {
+ enqueueSingle(asset);
+ }
+ else
+ {
+ log("Ignoring unsupported asset type: " + getQualifiedClassName(asset));
+ }
+ }
+ }
+
+ /** Enqueues a single asset with a custom name that can be used to access it later.
+ * If the asset is a texture, you can also add custom texture options.
+ *
+ * @param asset The asset that will be enqueued; accepts the same objects as the
+ * 'enqueue' method.
+ * @param name The name under which the asset will be found later. If you pass null or
+ * omit the parameter, it's attempted to generate a name automatically.
+ * @param options Custom options that will be used if 'asset' points to texture data.
+ * @return the name with which the asset was registered.
+ */
+ public function enqueueSingle(asset:Object, name:String=null,
+ options:TextureOptions=null):String
+ {
+ if (asset is Class)
+ asset = new asset();
+
+ var assetReference:AssetReference = new AssetReference(asset);
+ assetReference.name = name || getNameFromUrl(assetReference.url) || getUniqueName();
+ assetReference.extension = getExtensionFromUrl(assetReference.url);
+ assetReference.textureOptions = options || _textureOptions;
+ var logName:String = getFilenameFromUrl(assetReference.url) || assetReference.name;
+
+ _queue.push(assetReference);
+ log("Enqueuing '" + logName + "'");
+ return assetReference.name;
+ }
+
+ /** Removes the asset(s) with the given name(s) from the queue. Note that this won't work
+ * after loading has started, even if these specific assets have not yet been processed. */
+ public function dequeue(...assetNames):void
+ {
+ _queue = _queue.filter(function(asset:AssetReference, i:int, v:*):Boolean
+ {
+ return assetNames.indexOf(asset.name) == -1;
+ });
+ }
+
+ /** Empties the queue and aborts any pending load operations. */
+ public function purgeQueue():void
+ {
+ _queue.length = 0;
+ _dataLoader.close();
+ dispatchEventWith(Event.CANCEL);
+ }
+
+ /** Loads all enqueued assets asynchronously. The 'onComplete' callback will be executed
+ * once all assets have been loaded - even when there have been errors, which are
+ * forwarded to the optional 'onError' callback. The 'onProgress' function will be called
+ * with a 'ratio' between '0.0' and '1.0' and is also optional. Furthermore, all
+ * parameters of all the callbacks are optional.
+ *
+ *
When you call this method, the manager will save a reference to "Starling.current";
+ * all textures that are loaded will be accessible only from within this instance. Thus,
+ * if you are working with more than one Starling instance, be sure to call
+ * "makeCurrent()" on the appropriate instance before processing the queue.
+ *
+ * @param onComplete function(manager:AssetManager):void;
+ * @param onError function(error:String, asset:AssetReference):void;
+ * @param onProgress function(ratio:Number):void;
+ */
+ public function loadQueue(onComplete:Function,
+ onError:Function=null, onProgress:Function=null):void
+ {
+ if (_queue.length == 0)
+ {
+ finish();
+ return;
+ }
+
+ // By using an event listener, we can make a call to "cancel" affect
+ // only the currently active loading process(es).
+ addEventListener(Event.CANCEL, onCanceled);
+
+ var factoryHelper:AssetFactoryHelper = new AssetFactoryHelper();
+ factoryHelper.getNameFromUrlFunc = getNameFromUrl;
+ factoryHelper.getExtensionFromUrlFunc = getExtensionFromUrl;
+ factoryHelper.addPostProcessorFunc = addPostProcessor;
+ factoryHelper.addAssetFunc = addAsset;
+ factoryHelper.onRestoreFunc = onAssetRestored;
+ factoryHelper.dataLoader = _dataLoader;
+ factoryHelper.logFunc = log;
+
+ var i:int;
+ var self:AssetManager = this;
+ var canceled:Boolean = false;
+ var queue:Vector. = _queue.concat();
+ var numAssets:int = queue.length;
+ var numComplete:int = 0;
+ var numConnections:int = MathUtil.min(_numConnections, numAssets);
+ var assetProgress:Vector. = new Vector.(numAssets, true);
+ var postProcessors:Vector. = new [];
+
+ _starling = Starling.current;
+ _queue.length = 0;
+
+ for (i=0; i, progressRatios:Vector., index:int,
+ helper:AssetFactoryHelper, onComplete:Function, onProgress:Function,
+ onError:Function, onIntermediateError:Function):void
+ {
+ var referenceCount:int = queue.length;
+ var reference:AssetReference = queue[index];
+ progressRatios[index] = 0;
+
+ if (reference.url)
+ _dataLoader.load(reference.url, onLoadComplete, onLoadError, onLoadProgress);
+ else if (reference.data is AssetManager)
+ (reference.data as AssetManager).loadQueue(onManagerComplete, onIntermediateError, onLoadProgress);
+ else
+ setTimeout(onLoadComplete, 1, reference.data);
+
+ function onLoadComplete(data:Object, mimeType:String=null,
+ name:String=null, extension:String=null):void
+ {
+ if (_starling) _starling.makeCurrent();
+
+ onLoadProgress(1.0);
+
+ if (data) reference.data = data;
+ if (name) reference.name = name;
+ if (extension) reference.extension = extension;
+ if (mimeType) reference.mimeType = mimeType;
+
+ var assetFactory:AssetFactory = getFactoryFor(reference);
+ if (assetFactory == null)
+ execute(onAnyError, "Warning: no suitable factory found for '" + reference.name + "'");
+ else
+ assetFactory.create(reference, helper, onComplete, onFactoryError);
+ }
+
+ function onLoadProgress(ratio:Number):void
+ {
+ progressRatios[index] = ratio;
+
+ var totalRatio:Number = 0;
+ var multiplier:Number = 1.0 / referenceCount;
+
+ for (var k:int=0; k 0) totalRatio += multiplier * r;
+ }
+
+ execute(onProgress, MathUtil.min(totalRatio, 1.0));
+ }
+
+ function onLoadError(error:String):void
+ {
+ onLoadProgress(1.0);
+ execute(onAnyError, "Error loading " + reference.name + ": " + error);
+ }
+
+ function onAnyError(error:String):void
+ {
+ log(error);
+ execute(onError, error, reference);
+ }
+
+ function onFactoryError(error:String):void
+ {
+ execute(onAnyError, "Error creating " + reference.name + ": " + error);
+ }
+
+ function onManagerComplete():void
+ {
+ onComplete(reference.name, reference.data);
+ }
+ }
+
+ private function getFactoryFor(asset:AssetReference):AssetFactory
+ {
+ var numFactories:int = _assetFactories.length;
+ for (var i:int=0; iBeware: if the slot (name + type) was already taken, the existing object will be
+ * disposed and replaced by the new one.
+ *
+ * @param name The name with which the asset can be retrieved later. Must be
+ * unique within this asset type.
+ * @param asset The actual asset to add (e.g. a texture, a sound, etc).
+ * @param type The type of the asset. If omitted, the type will be determined
+ * automatically (which works for all standard types defined within
+ * the 'AssetType' class).
+ */
+ public function addAsset(name:String, asset:Object, type:String=null):void
+ {
+ type ||= AssetType.fromAsset(asset);
+
+ var store:Dictionary = _assets[type];
+ if (store == null)
+ {
+ store = new Dictionary();
+ _assets[type] = store;
+ }
+
+ log("Adding " + type + " '" + name + "'");
+
+ var prevAsset:Object = store[name];
+ if (prevAsset && prevAsset != asset)
+ {
+ log("Warning: name was already in use; disposing the previous " + type);
+ disposeAsset(prevAsset);
+ }
+
+ store[name] = asset;
+ }
+
+ /** Retrieves an asset of the given type, with the given name. If 'recursive' is true,
+ * the method will traverse included texture atlases and asset managers.
+ *
+ *
Typically, you will use one of the type-safe convenience methods instead, like
+ * 'getTexture', 'getSound', etc.
+ */
+ public function getAsset(type:String, name:String, recursive:Boolean=true):Object
+ {
+ if (recursive)
+ {
+ var managerStore:Dictionary = _assets[AssetType.ASSET_MANAGER];
+ if (managerStore)
+ {
+ for each (var manager:AssetManager in managerStore)
+ {
+ var asset:Object = manager.getAsset(type, name, true);
+ if (asset) return asset;
+ }
+ }
+
+ if (type == AssetType.TEXTURE)
+ {
+ var atlasStore:Dictionary = _assets[AssetType.TEXTURE_ATLAS];
+ if (atlasStore)
+ {
+ for each (var atlas:TextureAtlas in atlasStore)
+ {
+ var texture:Texture = atlas.getTexture(name);
+ if (texture) return texture;
+ }
+ }
+ }
+ }
+
+ var store:Dictionary = _assets[type];
+ if (store) return store[name];
+ else return null;
+ }
+
+ /** Retrieves an alphabetically sorted list of all assets that have the given type and
+ * start with the given prefix. If 'recursive' is true, the method will traverse included
+ * texture atlases and asset managers. */
+ public function getAssetNames(assetType:String, prefix:String="", recursive:Boolean=true,
+ out:Vector.=null):Vector.
+ {
+ out ||= new Vector.();
+
+ if (recursive)
+ {
+ var managerStore:Dictionary = _assets[AssetType.ASSET_MANAGER];
+ if (managerStore)
+ {
+ for each (var manager:AssetManager in managerStore)
+ manager.getAssetNames(assetType, prefix, true, out);
+ }
+
+ if (assetType == AssetType.TEXTURE)
+ {
+ var atlasStore:Dictionary = _assets[AssetType.TEXTURE_ATLAS];
+ if (atlasStore)
+ {
+ for each (var atlas:TextureAtlas in atlasStore)
+ atlas.getNames(prefix, out);
+ }
+ }
+ }
+
+ getDictionaryKeys(_assets[assetType], prefix, out);
+ out.sort(Array.CASEINSENSITIVE);
+ return out;
+ }
+
+ /** Removes the asset with the given name and type, and will optionally dispose it. */
+ public function removeAsset(assetType:String, name:String, dispose:Boolean=true):void
+ {
+ var store:Dictionary = _assets[assetType];
+ if (store)
+ {
+ var asset:Object = store[name];
+ if (asset)
+ {
+ log("Removing " + assetType + " '" + name + "'");
+ if (dispose) disposeAsset(asset);
+ delete store[name];
+ }
+ }
+ }
+
+ // convenience access methods
+
+ /** Returns a texture with a certain name. Includes textures stored inside atlases. */
+ public function getTexture(name:String):Texture
+ {
+ return getAsset(AssetType.TEXTURE, name) as Texture;
+ }
+
+ /** Returns all textures that start with a certain string, sorted alphabetically
+ * (especially useful for "MovieClip"). Includes textures stored inside atlases. */
+ public function getTextures(prefix:String="", out:Vector.=null):Vector.
+ {
+ if (out == null) out = new [];
+
+ for each (var name:String in getTextureNames(prefix, sNames))
+ out[out.length] = getTexture(name); // avoid 'push'
+
+ sNames.length = 0;
+ return out;
+ }
+
+ /** Returns all texture names that start with a certain string, sorted alphabetically.
+ * Includes textures stored inside atlases. */
+ public function getTextureNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.TEXTURE, prefix, true, out);
+ }
+
+ /** Returns a texture atlas with a certain name, or null if it's not found. */
+ public function getTextureAtlas(name:String):TextureAtlas
+ {
+ return getAsset(AssetType.TEXTURE_ATLAS, name) as TextureAtlas;
+ }
+
+ /** Returns all texture atlas names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getTextureAtlasNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.TEXTURE_ATLAS, prefix, true, out);
+ }
+
+ /** Returns a sound with a certain name, or null if it's not found. */
+ public function getSound(name:String):Sound
+ {
+ return getAsset(AssetType.SOUND, name) as Sound;
+ }
+
+ /** Returns all sound names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getSoundNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.SOUND, prefix, true, out);
+ }
+
+ /** Generates a new SoundChannel object to play back the sound. This method returns a
+ * SoundChannel object, which you can access to stop the sound and to control volume. */
+ public function playSound(name:String, startTime:Number=0, loops:int=0,
+ transform:SoundTransform=null):SoundChannel
+ {
+ var sound:Sound = getSound(name);
+ if (sound) return sound.play(startTime, loops, transform);
+ else return null;
+ }
+
+ /** Returns an XML with a certain name, or null if it's not found. */
+ public function getXml(name:String):XML
+ {
+ return getAsset(AssetType.XML_DOCUMENT, name) as XML;
+ }
+
+ /** Returns all XML names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getXmlNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.XML_DOCUMENT, prefix, true, out);
+ }
+
+ /** Returns an object with a certain name, or null if it's not found. Enqueued JSON
+ * data is parsed and can be accessed with this method. */
+ public function getObject(name:String):Object
+ {
+ return getAsset(AssetType.OBJECT, name);
+ }
+
+ /** Returns all object names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getObjectNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.OBJECT, prefix, true, out);
+ }
+
+ /** Returns a byte array with a certain name, or null if it's not found. */
+ public function getByteArray(name:String):ByteArray
+ {
+ return getAsset(AssetType.BYTE_ARRAY, name) as ByteArray;
+ }
+
+ /** Returns all byte array names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getByteArrayNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.BYTE_ARRAY, prefix, true, out);
+ }
+
+ /** Returns a bitmap font with a certain name, or null if it's not found. */
+ public function getBitmapFont(name:String):BitmapFont
+ {
+ return getAsset(AssetType.BITMAP_FONT, name) as BitmapFont;
+ }
+
+ /** Returns all bitmap font names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getBitmapFontNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.BITMAP_FONT, prefix, true, out);
+ }
+
+ /** Returns an asset manager with a certain name, or null if it's not found. */
+ public function getAssetManager(name:String):AssetManager
+ {
+ return getAsset(AssetType.ASSET_MANAGER, name) as AssetManager;
+ }
+
+ /** Returns all asset manager names that start with a certain string, sorted alphabetically.
+ * If you pass an out-vector, the names will be added to that vector. */
+ public function getAssetManagerNames(prefix:String="", out:Vector.=null):Vector.
+ {
+ return getAssetNames(AssetType.ASSET_MANAGER, prefix, true, out);
+ }
+
+ /** Removes a certain texture, optionally disposing it. */
+ public function removeTexture(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.TEXTURE, name, dispose);
+ }
+
+ /** Removes a certain texture atlas, optionally disposing it. */
+ public function removeTextureAtlas(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.TEXTURE_ATLAS, name, dispose);
+ }
+
+ /** Removes a certain sound. */
+ public function removeSound(name:String):void
+ {
+ removeAsset(AssetType.SOUND, name);
+ }
+
+ /** Removes a certain Xml object, optionally disposing it. */
+ public function removeXml(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.XML_DOCUMENT, name, dispose);
+ }
+
+ /** Removes a certain object. */
+ public function removeObject(name:String):void
+ {
+ removeAsset(AssetType.OBJECT, name);
+ }
+
+ /** Removes a certain byte array, optionally disposing its memory right away. */
+ public function removeByteArray(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.BYTE_ARRAY, name, dispose);
+ }
+
+ /** Removes a certain bitmap font, optionally disposing it. */
+ public function removeBitmapFont(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.BITMAP_FONT, name, dispose);
+ }
+
+ /** Removes a certain asset manager and optionally disposes it right away. */
+ public function removeAssetManager(name:String, dispose:Boolean=true):void
+ {
+ removeAsset(AssetType.ASSET_MANAGER, name, dispose);
+ }
+
+ // registration of factories
+
+ /** Registers a custom AssetFactory. If you use any priority > 0, the factory will
+ * be called before the default factories. The final factory to be invoked is the
+ * 'ByteArrayFactory', which is using a priority of '-100'. */
+ public function registerFactory(factory:AssetFactory, priority:int=0):void
+ {
+ factory.priority = priority;
+
+ _assetFactories.push(factory);
+ _assetFactories.sort(comparePriorities);
+ }
+
+ /** Unregisters the specified AssetFactory. */
+ public function unregisterFactory(factory:AssetFactory):void
+ {
+ var index:int = _assetFactories.indexOf(factory);
+ if (index != -1) _assetFactories.removeAt(index);
+ }
+
+ private static function comparePriorities(a:Object, b:Object):int
+ {
+ if (a.priority == b.priority) return 0;
+ return a.priority > b.priority ? -1 : 1;
+ }
+
+ // helpers
+
+ private function getFilenameFromUrl(url:String):String
+ {
+ if (url)
+ {
+ var matches:Array = NAME_REGEX.exec(decodeURIComponent(url));
+ if (matches && matches.length > 1) return matches[1];
+ }
+ return null;
+ }
+
+ /** This method is called internally to determine the name under which an asset will be
+ * accessible; override it if you need a custom naming scheme.
+ *
+ * @return the name to be used for the asset, or 'null' if it can't be determined. */
+ protected function getNameFromUrl(url:String):String
+ {
+ if (url)
+ {
+ var matches:Array = NAME_REGEX.exec(decodeURIComponent(url));
+ if (matches && matches.length > 2) return matches[2];
+ }
+ return null;
+ }
+
+ /** This method is called internally to determine the extension that's passed to the
+ * 'AssetFactory' (via the 'AssetReference'). Override it if you need to customize
+ * e.g. the extension of a server URL.
+ *
+ * @return the extension to be used for the asset, or an empty string if it can't be
+ * determined. */
+ protected function getExtensionFromUrl(url:String):String
+ {
+ if (url)
+ {
+ var matches:Array = NAME_REGEX.exec(decodeURIComponent(url));
+ if (matches && matches.length > 3) return matches[3];
+ }
+ return "";
+ }
+
+ /** Disposes the given asset. ByteArrays are cleared, XMLs are disposed using
+ * 'System.disposeXML'. If the object contains a 'dispose' method, it will be called.
+ * Override if you need to add custom cleanup code for a certain asset. */
+ protected function disposeAsset(asset:Object):void
+ {
+ if (asset is ByteArray) (asset as ByteArray).clear();
+ if (asset is XML) System.disposeXML(asset as XML);
+ if ("dispose" in asset) asset["dispose"]();
+ }
+
+ /** This method is called during loading of assets when 'verbose' is activated. Per
+ * default, it traces 'message' to the console. */
+ protected function log(message:String):void
+ {
+ if (_verbose) trace("[AssetManager]", message);
+ }
+
+ private static function getDictionaryKeys(dictionary:Dictionary, prefix:String="",
+ out:Vector.=null):Vector.
+ {
+ if (out == null) out = new [];
+ if (dictionary)
+ {
+ for (var name:String in dictionary)
+ if (name.indexOf(prefix) == 0)
+ out[out.length] = name; // avoid 'push'
+
+ out.sort(Array.CASEINSENSITIVE);
+ }
+ return out;
+ }
+
+ private static function getUniqueName():String
+ {
+ return NO_NAME + "-" + sNoNameCount++;
+ }
+
+ // properties
+
+ /** When activated, the class will trace information about added/enqueued assets.
+ * @default true */
+ public function get verbose():Boolean { return _verbose; }
+ public function set verbose(value:Boolean):void { _verbose = value; }
+
+ /** Returns the number of raw assets that have been enqueued, but not yet loaded. */
+ public function get numQueuedAssets():int { return _queue.length; }
+
+ /** The maximum number of parallel connections that are spawned when loading the queue.
+ * More connections can reduce loading times, but require more memory. @default 3. */
+ public function get numConnections():int { return _numConnections; }
+ public function set numConnections(value:int):void
+ {
+ _numConnections = MathUtil.min(1, value);
+ }
+
+ /** Textures will be created with the options set up in this object at the time of
+ * enqueuing. */
+ public function get textureOptions():TextureOptions { return _textureOptions; }
+ public function set textureOptions(value:TextureOptions):void { _textureOptions.copyFrom(value); }
+
+ /** The DataLoader is used to load any data from files or URLs. If you need to customize
+ * its behavior (e.g. to add a caching mechanism), assign your custom instance here. */
+ public function get dataLoader():DataLoader { return _dataLoader; }
+ public function set dataLoader(value:DataLoader):void { _dataLoader = value; }
+
+ /** Indicates if bitmap fonts should be registered with their "face" attribute from the
+ * font XML file. Per default, they are registered with the name of the texture file.
+ * @default false */
+ public function get registerBitmapFontsWithFontFace():Boolean
+ {
+ return _registerBitmapFontsWithFontFace;
+ }
+
+ public function set registerBitmapFontsWithFontFace(value:Boolean):void
+ {
+ _registerBitmapFontsWithFontFace = value;
+ }
+ }
+}
+
+import starling.assets.AssetManager;
+
+class AssetPostProcessor
+{
+ private var _priority:int;
+ private var _callback:Function;
+
+ public function AssetPostProcessor(callback:Function, priority:int)
+ {
+ if (callback == null || callback.length != 1)
+ throw new ArgumentError("callback must be a function " +
+ "accepting one 'AssetStore' parameter");
+
+ _callback = callback;
+ _priority = priority;
+ }
+
+ internal function execute(store:AssetManager):void
+ {
+ _callback(store);
+ }
+
+ public function get priority():int { return _priority; }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/assets/AssetReference.as b/mobile_version/src/starling/assets/AssetReference.as
new file mode 100644
index 00000000..d978f100
--- /dev/null
+++ b/mobile_version/src/starling/assets/AssetReference.as
@@ -0,0 +1,56 @@
+package starling.assets
+{
+ import starling.textures.TextureOptions;
+
+ /** The description of an asset to be created by an AssetFactory. */
+ public class AssetReference
+ {
+ private var _name:String;
+ private var _url:String;
+ private var _data:Object;
+ private var _mimeType:String;
+ private var _extension:String;
+ private var _textureOptions:TextureOptions;
+
+ /** Creates a new instance with the given data, which is typically some kind of file
+ * reference / URL or an instance of an asset class. If 'data' contains an URL, an
+ * equivalent value will be assigned to the 'url' property. */
+ public function AssetReference(data:Object)
+ {
+ _data = data;
+ _textureOptions = new TextureOptions();
+
+ if (data is String) _url = data as String;
+ else if ("url" in data) _url = data["url"] as String;
+ }
+
+ /** The name with which the asset should be added to the AssetManager. */
+ public function get name():String { return _name; }
+ public function set name(value:String):void { _name = value; }
+
+ /** The url from which the asset needs to be / has been loaded. */
+ public function get url():String { return _url; }
+ public function set url(value:String):void { _url = value; }
+
+ /** The raw data of the asset. This property often contains an URL; when it's passed
+ * to an AssetFactory, loading has already completed, and the property contains a
+ * ByteArray with the loaded data. */
+ public function get data():Object { return _data; }
+ public function set data(value:Object):void { _data = value; }
+
+ /** The mime type of the asset, if loaded from a server. */
+ public function get mimeType():String { return _mimeType; }
+ public function set mimeType(value:String):void { _mimeType = value; }
+
+ /** The file extension of the asset, if the filename or URL contains one. */
+ public function get extension():String { return _extension; }
+ public function set extension(value:String):void { _extension = value; }
+
+ /** The TextureOptions describing how to create a texture, if the asset references one. */
+ public function get textureOptions():TextureOptions { return _textureOptions; }
+ public function set textureOptions(value:TextureOptions):void
+ {
+ _textureOptions.copyFrom(value);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/AssetType.as b/mobile_version/src/starling/assets/AssetType.as
new file mode 100644
index 00000000..68631d28
--- /dev/null
+++ b/mobile_version/src/starling/assets/AssetType.as
@@ -0,0 +1,40 @@
+package starling.assets
+{
+ import flash.media.Sound;
+ import flash.media.Video;
+ import flash.utils.ByteArray;
+
+ import starling.errors.AbstractClassError;
+ import starling.text.BitmapFont;
+ import starling.textures.Texture;
+ import starling.textures.TextureAtlas;
+
+ /** An enumeration class containing all the asset types supported by the AssetManager. */
+ public class AssetType
+ {
+ /** @private */
+ public function AssetType() { throw new AbstractClassError(); }
+
+ public static const TEXTURE:String = "texture";
+ public static const TEXTURE_ATLAS:String = "textureAtlas";
+ public static const SOUND:String = "sound";
+ public static const XML_DOCUMENT:String = "xml";
+ public static const OBJECT:String = "object";
+ public static const BYTE_ARRAY:String = "byteArray";
+ public static const BITMAP_FONT:String = "bitmapFont";
+ public static const ASSET_MANAGER:String = "assetManager";
+
+ /** Figures out the asset type string from the type of the given instance. */
+ public static function fromAsset(asset:Object):String
+ {
+ if (asset is Texture) return TEXTURE;
+ else if (asset is TextureAtlas) return TEXTURE_ATLAS;
+ else if (asset is Sound) return SOUND;
+ else if (asset is XML) return XML_DOCUMENT;
+ else if (asset is ByteArray) return BYTE_ARRAY;
+ else if (asset is BitmapFont) return BITMAP_FONT;
+ else if (asset is AssetManager) return ASSET_MANAGER;
+ else return OBJECT;
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/AtfTextureFactory.as b/mobile_version/src/starling/assets/AtfTextureFactory.as
new file mode 100644
index 00000000..9e587170
--- /dev/null
+++ b/mobile_version/src/starling/assets/AtfTextureFactory.as
@@ -0,0 +1,73 @@
+package starling.assets
+{
+ import flash.utils.ByteArray;
+
+ import starling.textures.AtfData;
+ import starling.textures.Texture;
+ import starling.utils.execute;
+
+ /** This AssetFactory creates texture assets from ATF files. */
+ public class AtfTextureFactory extends AssetFactory
+ {
+ /** Creates a new instance. */
+ public function AtfTextureFactory()
+ {
+ addExtensions("atf"); // not used, actually, since we can parse the ATF header, anyway.
+ }
+
+ /** @inheritDoc */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ return (reference.data is ByteArray && AtfData.isAtfData(reference.data as ByteArray));
+ }
+
+ /** @inheritDoc */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ helper.executeWhenContextReady(createTexture);
+
+ function createTexture():void
+ {
+ var onReady:Function = reference.textureOptions.onReady as Function;
+ reference.textureOptions.onReady = function():void
+ {
+ execute(onReady, texture);
+ onComplete(reference.name, texture);
+ };
+
+ var texture:Texture = null;
+ var url:String = reference.url;
+
+ try { texture = Texture.fromData(reference.data, reference.textureOptions); }
+ catch (e:Error) { onError(e.message); }
+
+ if (url && texture)
+ {
+ texture.root.onRestore = function():void
+ {
+ helper.onBeginRestore();
+ helper.loadDataFromUrl(url, function(data:ByteArray):void
+ {
+ helper.executeWhenContextReady(function():void
+ {
+ try { texture.root.uploadAtfData(data); }
+ catch (e:Error) { helper.log("Texture restoration failed: " + e.message); }
+
+ helper.onEndRestore();
+ });
+ }, onReloadError);
+ };
+ }
+
+ reference.data = null; // prevent closures from keeping reference
+ }
+
+ function onReloadError(error:String):void
+ {
+ helper.log("Texture restoration failed for " + reference.url + ". " + error);
+ helper.onEndRestore();
+ }
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/BitmapTextureFactory.as b/mobile_version/src/starling/assets/BitmapTextureFactory.as
new file mode 100644
index 00000000..24915e4e
--- /dev/null
+++ b/mobile_version/src/starling/assets/BitmapTextureFactory.as
@@ -0,0 +1,167 @@
+package starling.assets
+{
+ import flash.display.Bitmap;
+ import flash.display.BitmapData;
+ import flash.display.Loader;
+ import flash.display.LoaderInfo;
+ import flash.events.Event;
+ import flash.events.IOErrorEvent;
+ import flash.system.ImageDecodingPolicy;
+ import flash.system.LoaderContext;
+ import flash.utils.ByteArray;
+
+ import starling.textures.Texture;
+ import starling.textures.TextureOptions;
+ import starling.utils.ByteArrayUtil;
+ import starling.utils.execute;
+
+ /** This AssetFactory creates texture assets from bitmaps and image files. */
+ public class BitmapTextureFactory extends AssetFactory
+ {
+ private static const MAGIC_NUMBERS_JPG:Array = [0xff, 0xd8];
+ private static const MAGIC_NUMBERS_PNG:Array = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
+ private static const MAGIC_NUMBERS_GIF:Array = [0x47, 0x49, 0x46, 0x38];
+
+ /** Creates a new instance. */
+ public function BitmapTextureFactory()
+ {
+ addMimeTypes("image/png", "image/jpg", "image/jpeg", "image/gif");
+ addExtensions("png", "jpg", "jpeg", "gif");
+ }
+
+ /** @inheritDoc */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ if (super.canHandle(reference) ||
+ reference.data is Bitmap || reference.data is BitmapData)
+ {
+ return true;
+ }
+ else if (reference.data is ByteArray)
+ {
+ var byteData:ByteArray = reference.data as ByteArray;
+ return ByteArrayUtil.startsWithBytes(byteData, MAGIC_NUMBERS_PNG) ||
+ ByteArrayUtil.startsWithBytes(byteData, MAGIC_NUMBERS_JPG) ||
+ ByteArrayUtil.startsWithBytes(byteData, MAGIC_NUMBERS_GIF);
+ }
+ else return false;
+ }
+
+ /** @inheritDoc */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ var texture:Texture = null;
+ var url:String = reference.url;
+ var data:Object = reference.data;
+ var name:String = reference.name;
+ var options:TextureOptions = reference.textureOptions;
+ var onReady:Function = reference.textureOptions.onReady as Function;
+
+ if (data is Bitmap)
+ onBitmapDataCreated((data as Bitmap).bitmapData);
+ else if (data is BitmapData)
+ onBitmapDataCreated(data as BitmapData);
+ else if (data is ByteArray)
+ createBitmapDataFromByteArray(data as ByteArray, onBitmapDataCreated, onError);
+
+ // prevent closures from keeping references
+ reference.data = data = null;
+
+ function onBitmapDataCreated(bitmapData:BitmapData):void
+ {
+ helper.executeWhenContextReady(createFromBitmapData, bitmapData);
+ }
+
+ function createFromBitmapData(bitmapData:BitmapData):void
+ {
+ options.onReady = complete;
+
+ try { texture = Texture.fromData(bitmapData, options); }
+ catch (e:Error) { onError(e.message); }
+
+ if (texture && url) texture.root.onRestore = restoreTexture;
+ }
+
+ function complete():void
+ {
+ execute(onReady, texture);
+ onComplete(name, texture);
+ }
+
+ function restoreTexture():void
+ {
+ helper.onBeginRestore();
+
+ reload(url, function(bitmapData:BitmapData):void
+ {
+ helper.executeWhenContextReady(function():void
+ {
+ try { texture.root.uploadBitmapData(bitmapData); }
+ catch (e:Error) { helper.log("Texture restoration failed: " + e.message); }
+
+ helper.onEndRestore();
+ });
+ });
+ }
+
+ function reload(url:String, onComplete:Function):void
+ {
+ helper.loadDataFromUrl(url, function(data:ByteArray):void
+ {
+ createBitmapDataFromByteArray(data, onComplete, onReloadError);
+ }, onReloadError);
+ }
+
+ function onReloadError(error:String):void
+ {
+ helper.log("Texture restoration failed for " + url + ". " + error);
+ helper.onEndRestore();
+ }
+ }
+
+ /** Called by 'create' to convert a ByteArray to a BitmapData.
+ *
+ * @param data A ByteArray that contains image data
+ * (like the contents of a PNG or JPG file).
+ * @param onComplete Called with the BitmapData when successful.
+ *
function(bitmapData:BitmapData):void;
+ * @param onError To be called when creation fails for some reason.
+ *
function(error:String):void
+ */
+ protected function createBitmapDataFromByteArray(data:ByteArray,
+ onComplete:Function, onError:Function):void
+ {
+ var loader:Loader = new Loader();
+ var loaderInfo:LoaderInfo = loader.contentLoaderInfo;
+ loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
+ loaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
+ var loaderContext:LoaderContext = new LoaderContext();
+ loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD;
+ loader.loadBytes(data, loaderContext);
+
+ function onIoError(event:IOErrorEvent):void
+ {
+ cleanup();
+ execute(onError, event.text);
+ }
+
+ function onLoaderComplete(event:Object):void
+ {
+ complete(event.target.content.bitmapData);
+ }
+
+ function complete(bitmapData:BitmapData):void
+ {
+ cleanup();
+ execute(onComplete, bitmapData);
+ }
+
+ function cleanup():void
+ {
+ loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIoError);
+ loaderInfo.removeEventListener(Event.COMPLETE, onLoaderComplete);
+ }
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/ByteArrayFactory.as b/mobile_version/src/starling/assets/ByteArrayFactory.as
new file mode 100644
index 00000000..79d02371
--- /dev/null
+++ b/mobile_version/src/starling/assets/ByteArrayFactory.as
@@ -0,0 +1,30 @@
+package starling.assets
+{
+ import flash.utils.ByteArray;
+
+ /** This AssetFactory forwards ByteArrays to the AssetManager. It's the fallback when
+ * no other factory can handle an asset reference (default priority: -100). */
+ public class ByteArrayFactory extends AssetFactory
+ {
+ /** Creates a new instance. */
+ public function ByteArrayFactory()
+ {
+ // not used, actually - this factory is used as a fallback with low priority
+ addExtensions("bin");
+ addMimeTypes("application/octet-stream");
+ }
+
+ /** @inheritDoc */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ return reference.data is ByteArray;
+ }
+
+ /** @inheritDoc */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ onComplete(reference.name, reference.data as ByteArray);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/DataLoader.as b/mobile_version/src/starling/assets/DataLoader.as
new file mode 100644
index 00000000..4fe81f7b
--- /dev/null
+++ b/mobile_version/src/starling/assets/DataLoader.as
@@ -0,0 +1,138 @@
+package starling.assets
+{
+ import flash.events.ErrorEvent;
+ import flash.events.Event;
+ import flash.events.HTTPStatusEvent;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.net.URLLoader;
+ import flash.net.URLLoaderDataFormat;
+ import flash.net.URLRequest;
+ import flash.utils.Dictionary;
+
+ import starling.utils.execute;
+
+ /** Loads binary data from a local or remote URL with a very simple callback system.
+ *
+ *
The DataLoader is used by the AssetManager to load any local or remote data.
+ * Its single purpose is to get the binary data that's stored at a specific URL.
+ *
+ *
You can use this class for your own purposes (as an easier to use 'URLLoader'
+ * alternative), or you can extend the class to modify the AssetManager's behavior.
+ * E.g. you could extend this class to add a caching mechanism for remote assets.
+ * Assign an instance of your extended class to the AssetManager's dataLoader
+ * property.
+ */
+ public class DataLoader
+ {
+ // This HTTPStatusEvent is only available in AIR
+ private static const HTTP_RESPONSE_STATUS:String = "httpResponseStatus";
+
+ private var _urlLoaders:Dictionary;
+
+ /** Creates a new DataLoader instance. */
+ public function DataLoader()
+ {
+ _urlLoaders = new Dictionary(true);
+ }
+
+ /** Loads the binary data from a specific URL. Always supply both 'onComplete' and
+ * 'onError' parameters; in case of an error, only the latter will be called.
+ *
+ *
The 'onComplete' callback may have up to four parameters, all of them being optional.
+ * If you pass a callback that just takes zero or one, it will work just as well. The
+ * additional parameters may be used to describe the name and type of the downloaded
+ * data. They are not provided by the base class, but the AssetManager will check
+ * if they are available.
+ *
+ * @param url a String containing an URL.
+ * @param onComplete will be called when the data has been loaded.
+ * function(data:ByteArray, mimeType:String, name:String, extension:String):void
+ * @param onError will be called in case of an error. The 2nd parameter is optional.
+ * function(error:String, httpStatus:int):void
+ * @param onProgress will be called multiple times with the current load ratio (0-1).
+ * function(ratio:Number):void
+ */
+ public function load(url:String, onComplete:Function,
+ onError:Function, onProgress:Function=null):void
+ {
+ var message:String;
+ var mimeType:String = null;
+ var httpStatus:int = 0;
+ var request:URLRequest = new URLRequest(url);
+ var loader:URLLoader = new URLLoader();
+ loader.dataFormat = URLLoaderDataFormat.BINARY;
+ loader.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
+ loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoadError);
+ loader.addEventListener(HTTP_RESPONSE_STATUS, onHttpResponseStatus);
+ loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
+ loader.addEventListener(Event.COMPLETE, onLoadComplete);
+ loader.load(request);
+
+ _urlLoaders[loader] = true;
+
+ function onHttpResponseStatus(event:HTTPStatusEvent):void
+ {
+ httpStatus = event.status;
+ mimeType = getHttpHeader(event["responseHeaders"], "Content-Type");
+ }
+
+ function onLoadError(event:ErrorEvent):void
+ {
+ cleanup();
+ message = event.type + " - " + event.text;
+ execute(onError, message);
+ }
+
+ function onLoadProgress(event:ProgressEvent):void
+ {
+ if (onProgress != null && event.bytesTotal > 0)
+ onProgress(event.bytesLoaded / event.bytesTotal);
+ }
+
+ function onLoadComplete(event:Object):void
+ {
+ cleanup();
+
+ if (httpStatus < 400)
+ execute(onComplete, loader.data, mimeType);
+ else
+ execute(onError, "Unexpected HTTP status '" + httpStatus + "'. URL: " +
+ request.url, httpStatus);
+ }
+
+ function cleanup():void
+ {
+ loader.removeEventListener(IOErrorEvent.IO_ERROR, onLoadError);
+ loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoadError);
+ loader.removeEventListener(HTTP_RESPONSE_STATUS, onHttpResponseStatus);
+ loader.removeEventListener(ProgressEvent.PROGRESS, onLoadProgress);
+ loader.removeEventListener(Event.COMPLETE, onLoadComplete);
+ delete _urlLoaders[loader];
+ }
+ }
+
+ /** Aborts all current load operations. The loader can still be used, though. */
+ public function close():void
+ {
+ for (var loader:* in _urlLoaders)
+ {
+ try { loader.close(); }
+ catch (e:Error) {}
+ }
+
+ _urlLoaders = new Dictionary(true);
+ }
+
+ private static function getHttpHeader(headers:Array, headerName:String):String
+ {
+ if (headers)
+ {
+ for each (var header:Object in headers)
+ if (header.name == headerName) return header.value;
+ }
+ return null;
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/JsonFactory.as b/mobile_version/src/starling/assets/JsonFactory.as
new file mode 100644
index 00000000..8f8494c9
--- /dev/null
+++ b/mobile_version/src/starling/assets/JsonFactory.as
@@ -0,0 +1,40 @@
+package starling.assets
+{
+ import flash.utils.ByteArray;
+
+ import starling.utils.ByteArrayUtil;
+
+ /** This AssetFactory creates objects from JSON data. */
+ public class JsonFactory extends AssetFactory
+ {
+ /** Creates a new instance. */
+ public function JsonFactory()
+ {
+ addExtensions("json");
+ addMimeTypes("application/json", "text/json");
+ }
+
+ /** @inheritDoc */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ return super.canHandle(reference) || (reference.data is ByteArray &&
+ ByteArrayUtil.startsWithString(reference.data as ByteArray, "{"));
+ }
+
+ /** @inheritDoc */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ try
+ {
+ var bytes:ByteArray = reference.data as ByteArray;
+ var object:Object = JSON.parse(bytes.readUTFBytes(bytes.length));
+ onComplete(reference.name, object);
+ }
+ catch (e:Error)
+ {
+ onError("Could not parse JSON: " + e.message);
+ }
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/SoundFactory.as b/mobile_version/src/starling/assets/SoundFactory.as
new file mode 100644
index 00000000..84e097b6
--- /dev/null
+++ b/mobile_version/src/starling/assets/SoundFactory.as
@@ -0,0 +1,60 @@
+package starling.assets
+{
+ import flash.media.Sound;
+ import flash.utils.ByteArray;
+
+ import starling.utils.ByteArrayUtil;
+
+ /** This AssetFactory creates sound assets. */
+ public class SoundFactory extends AssetFactory
+ {
+ private static const MAGIC_NUMBERS_A:Array = [0xFF, 0xFB];
+ private static const MAGIC_NUMBERS_B:Array = [0x49, 0x44, 0x33];
+
+ /** Creates a new instance. */
+ public function SoundFactory()
+ {
+ addMimeTypes("audio/mp3", "audio/mpeg3", "audio/mpeg");
+ addExtensions("mp3");
+ }
+
+ /** @inheritDoc */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ if (reference.data is Sound || super.canHandle(reference))
+ return true;
+ else if (reference.data is ByteArray)
+ {
+ var byteData:ByteArray = reference.data as ByteArray;
+ return ByteArrayUtil.startsWithBytes(byteData, MAGIC_NUMBERS_A) ||
+ ByteArrayUtil.startsWithBytes(byteData, MAGIC_NUMBERS_B);
+ }
+ else return false;
+ }
+
+ /** @inheritDoc */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ var sound:Sound = reference.data as Sound;
+ var bytes:ByteArray = reference.data as ByteArray;
+
+ if (bytes)
+ {
+ try
+ {
+ sound = new Sound();
+ sound.loadCompressedDataFromByteArray(bytes, bytes.length);
+ }
+ catch (e:Error)
+ {
+ onError("Could not load sound data: " + e.message);
+ return;
+ }
+
+ }
+
+ onComplete(reference.name, sound);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/assets/XmlFactory.as b/mobile_version/src/starling/assets/XmlFactory.as
new file mode 100644
index 00000000..54af6099
--- /dev/null
+++ b/mobile_version/src/starling/assets/XmlFactory.as
@@ -0,0 +1,84 @@
+package starling.assets
+{
+ import flash.utils.ByteArray;
+
+ import starling.text.BitmapFont;
+ import starling.text.TextField;
+ import starling.textures.Texture;
+ import starling.textures.TextureAtlas;
+ import starling.utils.ByteArrayUtil;
+
+ /** This AssetFactory creates XML assets, texture atlases and bitmap fonts. */
+ public class XmlFactory extends AssetFactory
+ {
+ /** Creates a new instance. */
+ public function XmlFactory()
+ {
+ addMimeTypes("application/xml", "text/xml");
+ addExtensions("xml", "fnt");
+ }
+
+ /** Returns true if mime type or extension fit for XML data, or if the data starts
+ * with a "<" character. */
+ override public function canHandle(reference:AssetReference):Boolean
+ {
+ return super.canHandle(reference) || (reference.data is ByteArray &&
+ ByteArrayUtil.startsWithString(reference.data as ByteArray, "<"));
+ }
+
+ /** Creates the XML asset and passes it to 'onComplete'. If the XML contains a
+ * TextureAtlas or a BitmapFont, adds suitable post processors. */
+ override public function create(reference:AssetReference, helper:AssetFactoryHelper,
+ onComplete:Function, onError:Function):void
+ {
+ var xml:XML = reference.data as XML;
+ var bytes:ByteArray = reference.data as ByteArray;
+
+ if (bytes)
+ {
+ try { xml = new XML(bytes); }
+ catch (e:Error)
+ {
+ onError("Could not parse XML: " + e.message);
+ return;
+ }
+ }
+
+ var rootNode:String = xml.localName();
+
+ if (rootNode == "TextureAtlas")
+ helper.addPostProcessor(textureAtlasPostProcessor, 100);
+ else if (rootNode == "font")
+ helper.addPostProcessor(bitmapFontPostProcessor);
+
+ onComplete(reference.name, xml);
+
+ // prevent closures from keeping references
+ reference.data = bytes = null;
+
+ function textureAtlasPostProcessor(store:AssetManager):void
+ {
+ var name:String = helper.getNameFromUrl(xml.@imagePath.toString());
+ var texture:Texture = store.getTexture(name);
+ if (texture) store.addAsset(name, new TextureAtlas(texture, xml));
+ else helper.log("Cannot create atlas: texture '" + name + "' is missing.");
+ }
+
+ function bitmapFontPostProcessor(store:AssetManager):void
+ {
+ var textureName:String = helper.getNameFromUrl(xml.pages.page.@file.toString());
+ var texture:Texture = store.getTexture(textureName);
+ var fontName:String = store.registerBitmapFontsWithFontFace ?
+ xml.info.@face.toString() : textureName;
+
+ if (texture)
+ {
+ var bitmapFont:BitmapFont = new BitmapFont(texture, xml);
+ store.addAsset(fontName, bitmapFont);
+ TextField.registerCompositor(bitmapFont, fontName);
+ }
+ else helper.log("Cannot create bitmap font: texture '" + textureName + "' is missing.");
+ }
+ }
+ }
+}
diff --git a/mobile_version/src/starling/core/Starling.as b/mobile_version/src/starling/core/Starling.as
new file mode 100644
index 00000000..042eedc1
--- /dev/null
+++ b/mobile_version/src/starling/core/Starling.as
@@ -0,0 +1,1051 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.core
+{
+ import flash.display.Shape;
+ import flash.display.Sprite;
+ import flash.display.Stage3D;
+ import flash.display.StageAlign;
+ import flash.display.StageScaleMode;
+ import flash.display3D.Context3D;
+ import flash.display3D.Context3DProfile;
+ import flash.errors.IllegalOperationError;
+ import flash.events.ErrorEvent;
+ import flash.events.Event;
+ import flash.events.KeyboardEvent;
+ import flash.events.MouseEvent;
+ import flash.events.TouchEvent;
+ import flash.geom.Rectangle;
+ import flash.system.Capabilities;
+ import flash.text.TextField;
+ import flash.text.TextFieldAutoSize;
+ import flash.text.TextFormat;
+ import flash.text.TextFormatAlign;
+ import flash.ui.Mouse;
+ import flash.ui.Multitouch;
+ import flash.ui.MultitouchInputMode;
+ import flash.utils.getTimer;
+ import flash.utils.setTimeout;
+
+ import starling.animation.Juggler;
+ import starling.display.DisplayObject;
+ import starling.display.Stage;
+ import starling.events.EventDispatcher;
+ import starling.events.ResizeEvent;
+ import starling.events.TouchPhase;
+ import starling.events.TouchProcessor;
+ import starling.rendering.Painter;
+ import starling.utils.Align;
+ import starling.utils.RectangleUtil;
+ import starling.utils.SystemUtil;
+
+ /** Dispatched when a new render context is created. The 'data' property references the context. */
+ [Event(name="context3DCreate", type="starling.events.Event")]
+
+ /** Dispatched when the root class has been created. The 'data' property references that object. */
+ [Event(name="rootCreated", type="starling.events.Event")]
+
+ /** Dispatched when a fatal error is encountered. The 'data' property contains an error string. */
+ [Event(name="fatalError", type="starling.events.Event")]
+
+ /** Dispatched when the display list is about to be rendered. This event provides the last
+ * opportunity to make changes before the display list is rendered. */
+ [Event(name="render", type="starling.events.Event")]
+
+ /** The Starling class represents the core of the Starling framework.
+ *
+ *
The Starling framework makes it possible to create 2D applications and games that make
+ * use of the Stage3D architecture introduced in Flash Player 11. It implements a display tree
+ * system that is very similar to that of conventional Flash, while leveraging modern GPUs
+ * to speed up rendering.
+ *
+ *
The Starling class represents the link between the conventional Flash display tree and
+ * the Starling display tree. To create a Starling-powered application, you have to create
+ * an instance of the Starling class:
+ *
+ *
var starling:Starling = new Starling(Game, stage);
+ *
+ *
The first parameter has to be a Starling display object class, e.g. a subclass of
+ * starling.display.Sprite. In the sample above, the class "Game" is the
+ * application root. An instance of "Game" will be created as soon as Starling is initialized.
+ * The second parameter is the conventional (Flash) stage object. Per default, Starling will
+ * display its contents directly below the stage.
+ *
+ *
It is recommended to store the Starling instance as a member variable, to make sure
+ * that the Garbage Collector does not destroy it. After creating the Starling object, you
+ * have to start it up like this:
+ *
+ *
starling.start();
+ *
+ *
It will now render the contents of the "Game" class in the frame rate that is set up for
+ * the application (as defined in the Flash stage).
+ *
+ * Context3D Profiles
+ *
+ *
Stage3D supports different rendering profiles, and Starling works with all of them. The
+ * last parameter of the Starling constructor allows you to choose which profile you want.
+ * The following profiles are available:
+ *
+ *
+ *
BASELINE_CONSTRAINED: provides the broadest hardware reach. If you develop for the
+ * browser, this is the profile you should test with.
+ *
BASELINE: recommend for any mobile application, as it allows Starling to use a more
+ * memory efficient texture type (RectangleTextures). It also supports more complex
+ * AGAL code.
+ *
BASELINE_EXTENDED: adds support for textures up to 4096x4096 pixels. This is
+ * especially useful on mobile devices with very high resolutions.
+ *
STANDARD_CONSTRAINED, STANDARD, STANDARD_EXTENDED: each provide more AGAL features,
+ * among other things. Most Starling games will not gain much from them.
+ *
+ *
+ *
The recommendation is to deploy your app with the profile "auto" (which makes Starling
+ * pick the best available of those), but to test it in all available profiles.
+ *
+ * Accessing the Starling object
+ *
+ *
From within your application, you can access the current Starling object anytime
+ * through the static method Starling.current. It will return the active Starling
+ * instance (most applications will only have one Starling object, anyway).
+ *
+ * Viewport
+ *
+ *
The area the Starling content is rendered into is, per default, the complete size of the
+ * stage. You can, however, use the "viewPort" property to change it. This can be useful
+ * when you want to render only into a part of the screen, or if the player size changes. For
+ * the latter, you can listen to the RESIZE-event dispatched by the Starling
+ * stage.
+ *
+ * Native overlay
+ *
+ *
Sometimes you will want to display native Flash content on top of Starling. That's what the
+ * nativeOverlay property is for. It returns a Flash Sprite lying directly
+ * on top of the Starling content. You can add conventional Flash objects to that overlay.
+ *
+ *
Beware, though, that conventional Flash content on top of 3D content can lead to
+ * performance penalties on some (mobile) platforms. For that reason, always remove all child
+ * objects from the overlay when you don't need them any longer.
+ *
+ * Multitouch
+ *
+ *
Starling supports multitouch input on devices that provide it. During development,
+ * where most of us are working with a conventional mouse and keyboard, Starling can simulate
+ * multitouch events with the help of the "Shift" and "Ctrl" (Mac: "Cmd") keys. Activate
+ * this feature by enabling the simulateMultitouch property.
+ *
+ * Skipping Unchanged Frames
+ *
+ *
It happens surprisingly often in an app or game that a scene stays completely static for
+ * several frames. So why redraw the stage at all in those situations? That's exactly the
+ * point of the skipUnchangedFrames-property. If enabled, static scenes are
+ * recognized as such and the back buffer is simply left as it is. On a mobile device, the
+ * impact of this feature can't be overestimated! There's simply no better way to enhance
+ * battery life. Make it a habit to always activate it; look at the documentation of the
+ * corresponding property for details.
+ *
+ * Handling a lost render context
+ *
+ *
On some operating systems and under certain conditions (e.g. returning from system
+ * sleep), Starling's stage3D render context may be lost. Starling will try to recover
+ * from a lost context automatically; to be able to do this, it will cache textures in
+ * RAM. This will take up quite a bit of extra memory, though, which might be problematic
+ * especially on mobile platforms. To avoid the higher memory footprint, it's recommended
+ * to load your textures with Starling's "AssetManager"; it is smart enough to recreate a
+ * texture directly from its origin.
+ *
+ *
In case you want to react to a context loss manually, Starling dispatches an event with
+ * the type "Event.CONTEXT3D_CREATE" when the context is restored, and textures will execute
+ * their root.onRestore callback, to which you can attach your own logic.
+ * Refer to the "Texture" class for more information.
+ *
+ * Sharing a 3D Context
+ *
+ *
Per default, Starling handles the Stage3D context itself. If you want to combine
+ * Starling with another Stage3D engine, however, this may not be what you want. In this case,
+ * you can make use of the shareContext property:
+ *
+ *
+ *
Manually create and configure a context3D object that both frameworks can work with
+ * (ideally through RenderUtil.requestContext3D and
+ * context.configureBackBuffer).
+ *
Initialize Starling with the stage3D instance that contains that configured context.
+ * This will automatically enable shareContext.
+ *
Call start() on your Starling instance (as usual). This will make
+ * Starling queue input events (keyboard/mouse/touch).
+ *
Create a game loop (e.g. using the native ENTER_FRAME event) and let it
+ * call Starling's nextFrame as well as the equivalent method of the other
+ * Stage3D engine. Surround those calls with context.clear() and
+ * context.present().
+ *
+ *
+ *
The Starling wiki contains a tutorial with more
+ * information about this topic.
+ *
+ * @see starling.utils.AssetManager
+ * @see starling.textures.Texture
+ *
+ */
+ public class Starling extends EventDispatcher
+ {
+ /** The version of the Starling framework. */
+ public static const VERSION:String = "2.1";
+
+ // members
+
+ private var _stage:Stage; // starling.display.stage!
+ private var _rootClass:Class;
+ private var _root:DisplayObject;
+ private var _juggler:Juggler;
+ private var _painter:Painter;
+ private var _touchProcessor:TouchProcessor;
+ private var _antiAliasing:int;
+ private var _frameTimestamp:Number;
+ private var _frameID:uint;
+ private var _leftMouseDown:Boolean;
+ private var _statsDisplay:StatsDisplay;
+ private var _started:Boolean;
+ private var _rendering:Boolean;
+ private var _supportHighResolutions:Boolean;
+ private var _skipUnchangedFrames:Boolean;
+ private var _showStats:Boolean;
+
+ private var _viewPort:Rectangle;
+ private var _previousViewPort:Rectangle;
+ private var _clippedViewPort:Rectangle;
+
+ private var _nativeStage:flash.display.Stage;
+ private var _nativeStageEmpty:Boolean;
+ private var _nativeOverlay:Sprite;
+
+ private static var sCurrent:Starling;
+ private static var sAll:Vector. = new [];
+
+ // construction
+
+ /** Creates a new Starling instance.
+ * @param rootClass A subclass of 'starling.display.DisplayObject'. It will be created
+ * as soon as initialization is finished and will become the first child
+ * of the Starling stage. Pass null if you don't want to
+ * create a root object right away. (You can use the
+ * rootClass property later to make that happen.)
+ * @param stage The Flash (2D) stage.
+ * @param viewPort A rectangle describing the area into which the content will be
+ * rendered. Default: stage size
+ * @param stage3D The Stage3D object into which the content will be rendered. If it
+ * already contains a context, sharedContext will be set
+ * to true. Default: the first available Stage3D.
+ * @param renderMode The Context3D render mode that should be requested.
+ * Use this parameter if you want to force "software" rendering.
+ * @param profile The Context3D profile that should be requested.
+ *
+ *
+ *
If you pass a profile String, this profile is enforced.
+ *
Pass an Array of profiles to make Starling pick the first
+ * one that works (starting with the first array element).
+ *
Pass the String "auto" to make Starling pick the best available
+ * profile automatically.
+ *
+ */
+ public function Starling(rootClass:Class, stage:flash.display.Stage,
+ viewPort:Rectangle=null, stage3D:Stage3D=null,
+ renderMode:String="auto", profile:Object="auto")
+ {
+ if (stage == null) throw new ArgumentError("Stage must not be null");
+ if (viewPort == null) viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
+ if (stage3D == null) stage3D = stage.stage3Ds[0];
+
+ // TODO it might make sense to exchange the 'renderMode' and 'profile' parameters.
+
+ SystemUtil.initialize();
+ sAll.push(this);
+ makeCurrent();
+
+ _rootClass = rootClass;
+ _viewPort = viewPort;
+ _previousViewPort = new Rectangle();
+ _stage = new Stage(viewPort.width, viewPort.height, stage.color);
+ _nativeOverlay = new Sprite();
+ _nativeStage = stage;
+ _nativeStage.addChild(_nativeOverlay);
+ _touchProcessor = new TouchProcessor(_stage);
+ _juggler = new Juggler();
+ _antiAliasing = 0;
+ _supportHighResolutions = false;
+ _painter = new Painter(stage3D);
+ _frameTimestamp = getTimer() / 1000.0;
+ _frameID = 1;
+
+ // all other modes are problematic in Starling, so we force those here
+ stage.scaleMode = StageScaleMode.NO_SCALE;
+ stage.align = StageAlign.TOP_LEFT;
+
+ // register touch/mouse event handlers
+ for each (var touchEventType:String in touchEventTypes)
+ stage.addEventListener(touchEventType, onTouch, false, 0, true);
+
+ // register other event handlers
+ stage.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
+ stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey, false, 0, true);
+ stage.addEventListener(KeyboardEvent.KEY_UP, onKey, false, 0, true);
+ stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
+ stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave, false, 0, true);
+
+ stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 10, true);
+ stage3D.addEventListener(ErrorEvent.ERROR, onStage3DError, false, 10, true);
+
+ if (_painter.shareContext)
+ {
+ setTimeout(initialize, 1); // we don't call it right away, because Starling should
+ // behave the same way with or without a shared context
+ }
+ else
+ {
+ if (!SystemUtil.supportsDepthAndStencil)
+ trace("[Starling] Mask support requires 'depthAndStencil' to be enabled" +
+ " in the application descriptor.");
+
+ _painter.requestContext3D(renderMode, profile);
+ }
+ }
+
+ /** Disposes all children of the stage and the render context; removes all registered
+ * event listeners. */
+ public function dispose():void
+ {
+ stop(true);
+
+ _nativeStage.removeEventListener(Event.ENTER_FRAME, onEnterFrame, false);
+ _nativeStage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey, false);
+ _nativeStage.removeEventListener(KeyboardEvent.KEY_UP, onKey, false);
+ _nativeStage.removeEventListener(Event.RESIZE, onResize, false);
+ _nativeStage.removeEventListener(Event.MOUSE_LEAVE, onMouseLeave, false);
+ _nativeStage.removeChild(_nativeOverlay);
+
+ stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false);
+ stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextRestored, false);
+ stage3D.removeEventListener(ErrorEvent.ERROR, onStage3DError, false);
+
+ for each (var touchEventType:String in touchEventTypes)
+ _nativeStage.removeEventListener(touchEventType, onTouch, false);
+
+ _touchProcessor.dispose();
+ _painter.dispose();
+ _stage.dispose();
+
+ var index:int = sAll.indexOf(this);
+ if (index != -1) sAll.removeAt(index);
+ if (sCurrent == this) sCurrent = null;
+ }
+
+ // functions
+
+ private function initialize():void
+ {
+ makeCurrent();
+ updateViewPort(true);
+
+ // ideal time: after viewPort setup, before root creation
+ dispatchEventWith(Event.CONTEXT3D_CREATE, false, context);
+
+ initializeRoot();
+ _frameTimestamp = getTimer() / 1000.0;
+ }
+
+ private function initializeRoot():void
+ {
+ if (_root == null && _rootClass != null)
+ {
+ _root = new _rootClass() as DisplayObject;
+ if (_root == null) throw new Error("Invalid root class: " + _rootClass);
+ _stage.addChildAt(_root, 0);
+
+ dispatchEventWith(starling.events.Event.ROOT_CREATED, false, _root);
+ }
+ }
+
+ /** Calls advanceTime() (with the time that has passed since the last frame)
+ * and render(). */
+ public function nextFrame():void
+ {
+ var now:Number = getTimer() / 1000.0;
+ var passedTime:Number = now - _frameTimestamp;
+ _frameTimestamp = now;
+
+ // to avoid overloading time-based animations, the maximum delta is truncated.
+ if (passedTime > 1.0) passedTime = 1.0;
+
+ // after about 25 days, 'getTimer()' will roll over. A rare event, but still ...
+ if (passedTime < 0.0) passedTime = 1.0 / _nativeStage.frameRate;
+
+ advanceTime(passedTime);
+ render();
+ }
+
+ /** Dispatches ENTER_FRAME events on the display list, advances the Juggler
+ * and processes touches. */
+ public function advanceTime(passedTime:Number):void
+ {
+ if (!contextValid)
+ return;
+
+ makeCurrent();
+
+ _touchProcessor.advanceTime(passedTime);
+ _stage.advanceTime(passedTime);
+ _juggler.advanceTime(passedTime);
+ }
+
+ /** Renders the complete display list. Before rendering, the context is cleared; afterwards,
+ * it is presented (to avoid this, enable shareContext).
+ *
+ *
This method also dispatches an Event.RENDER-event on the Starling
+ * instance. That's the last opportunity to make changes before the display list is
+ * rendered.
*/
+ public function render():void
+ {
+ if (!contextValid)
+ return;
+
+ makeCurrent();
+ updateViewPort();
+
+ var doRedraw:Boolean = _stage.requiresRedraw || mustAlwaysRender;
+ if (doRedraw)
+ {
+ dispatchEventWith(starling.events.Event.RENDER);
+
+ var shareContext:Boolean = _painter.shareContext;
+ var scaleX:Number = _viewPort.width / _stage.stageWidth;
+ var scaleY:Number = _viewPort.height / _stage.stageHeight;
+
+ _painter.nextFrame();
+ _painter.pixelSize = 1.0 / contentScaleFactor;
+ _painter.state.setProjectionMatrix(
+ _viewPort.x < 0 ? -_viewPort.x / scaleX : 0.0,
+ _viewPort.y < 0 ? -_viewPort.y / scaleY : 0.0,
+ _clippedViewPort.width / scaleX,
+ _clippedViewPort.height / scaleY,
+ _stage.stageWidth, _stage.stageHeight, _stage.cameraPosition);
+
+ if (!shareContext)
+ _painter.clear(_stage.color, 0.0);
+
+ _stage.render(_painter);
+ _painter.finishFrame();
+ _painter.frameID = ++_frameID;
+
+ if (!shareContext)
+ _painter.present();
+ }
+
+ if (_statsDisplay)
+ {
+ _statsDisplay.drawCount = _painter.drawCount;
+ if (!doRedraw) _statsDisplay.markFrameAsSkipped();
+ }
+ }
+
+ private function updateViewPort(forceUpdate:Boolean=false):void
+ {
+ // the last set viewport is stored in a variable; that way, people can modify the
+ // viewPort directly (without a copy) and we still know if it has changed.
+
+ if (forceUpdate || !RectangleUtil.compare(_viewPort, _previousViewPort))
+ {
+ _previousViewPort.setTo(_viewPort.x, _viewPort.y, _viewPort.width, _viewPort.height);
+
+ // Constrained mode requires that the viewport is within the native stage bounds;
+ // thus, we use a clipped viewport when configuring the back buffer. (In baseline
+ // mode, that's not necessary, but it does not hurt either.)
+
+ _clippedViewPort = _viewPort.intersection(
+ new Rectangle(0, 0, _nativeStage.stageWidth, _nativeStage.stageHeight));
+
+ var contentScaleFactor:Number =
+ _supportHighResolutions ? _nativeStage.contentsScaleFactor : 1.0;
+
+ _painter.configureBackBuffer(_clippedViewPort, contentScaleFactor,
+ _antiAliasing, true);
+ }
+ }
+
+ private function updateNativeOverlay():void
+ {
+ _nativeOverlay.x = _viewPort.x;
+ _nativeOverlay.y = _viewPort.y;
+ _nativeOverlay.scaleX = _viewPort.width / _stage.stageWidth;
+ _nativeOverlay.scaleY = _viewPort.height / _stage.stageHeight;
+ }
+
+ /** Stops Starling right away and displays an error message on the native overlay.
+ * This method will also cause Starling to dispatch a FATAL_ERROR event. */
+ public function stopWithFatalError(message:String):void
+ {
+ var background:Shape = new Shape();
+ background.graphics.beginFill(0x0, 0.8);
+ background.graphics.drawRect(0, 0, _stage.stageWidth, _stage.stageHeight);
+ background.graphics.endFill();
+
+ var textField:TextField = new TextField();
+ var textFormat:TextFormat = new TextFormat("Verdana", 14, 0xFFFFFF);
+ textFormat.align = TextFormatAlign.CENTER;
+ textField.defaultTextFormat = textFormat;
+ textField.wordWrap = true;
+ textField.width = _stage.stageWidth * 0.75;
+ textField.autoSize = TextFieldAutoSize.CENTER;
+ textField.text = message;
+ textField.x = (_stage.stageWidth - textField.width) / 2;
+ textField.y = (_stage.stageHeight - textField.height) / 2;
+ textField.background = true;
+ textField.backgroundColor = 0x550000;
+
+ updateNativeOverlay();
+ nativeOverlay.addChild(background);
+ nativeOverlay.addChild(textField);
+ stop(true);
+
+ trace("[Starling]", message);
+ dispatchEventWith(starling.events.Event.FATAL_ERROR, false, message);
+ }
+
+ /** Make this Starling instance the current one. */
+ public function makeCurrent():void
+ {
+ sCurrent = this;
+ }
+
+ /** As soon as Starling is started, it will queue input events (keyboard/mouse/touch);
+ * furthermore, the method nextFrame will be called once per Flash Player
+ * frame. (Except when shareContext is enabled: in that case, you have to
+ * call that method manually.) */
+ public function start():void
+ {
+ _started = _rendering = true;
+ _frameTimestamp = getTimer() / 1000.0;
+
+ // mainly for Android: force redraw when app moves into foreground
+ setTimeout(setRequiresRedraw, 100);
+ }
+
+ /** Stops all logic and input processing, effectively freezing the app in its current state.
+ * Per default, rendering will continue: that's because the classic display list
+ * is only updated when stage3D is. (If Starling stopped rendering, conventional Flash
+ * contents would freeze, as well.)
+ *
+ *
However, if you don't need classic Flash contents, you can stop rendering, too.
+ * On some mobile systems (e.g. iOS), you are even required to do so if you have
+ * activated background code execution.
+ */
+ public function stop(suspendRendering:Boolean=false):void
+ {
+ _started = false;
+ _rendering = !suspendRendering;
+ }
+
+ /** Makes sure that the next frame is actually rendered.
+ *
+ *
When skipUnchangedFrames is enabled, some situations require that you
+ * manually force a redraw, e.g. when a RenderTexture is changed. This method is the
+ * easiest way to do so; it's just a shortcut to stage.setRequiresRedraw().
+ *
+ */
+ public function setRequiresRedraw():void
+ {
+ _stage.setRequiresRedraw();
+ }
+
+ // event handlers
+
+ private function onStage3DError(event:ErrorEvent):void
+ {
+ if (event.errorID == 3702)
+ {
+ var mode:String = Capabilities.playerType == "Desktop" ? "renderMode" : "wmode";
+ stopWithFatalError("Context3D not available! Possible reasons: wrong " + mode +
+ " or missing device support.");
+ }
+ else
+ stopWithFatalError("Stage3D error: " + event.text);
+ }
+
+ private function onContextCreated(event:Event):void
+ {
+ stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
+ stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextRestored, false, 10, true);
+
+ trace("[Starling] Context ready. Display Driver:", context.driverInfo);
+ initialize();
+ }
+
+ private function onContextRestored(event:Event):void
+ {
+ trace("[Starling] Context restored.");
+ updateViewPort(true);
+ dispatchEventWith(Event.CONTEXT3D_CREATE, false, context);
+ }
+
+ private function onEnterFrame(event:Event):void
+ {
+ // On mobile, the native display list is only updated on stage3D draw calls.
+ // Thus, we render even when Starling is paused.
+
+ if (!shareContext)
+ {
+ if (_started) nextFrame();
+ else if (_rendering) render();
+ }
+
+ updateNativeOverlay();
+ }
+
+ private function onKey(event:KeyboardEvent):void
+ {
+ if (!_started) return;
+
+ var keyEvent:starling.events.KeyboardEvent = new starling.events.KeyboardEvent(
+ event.type, event.charCode, event.keyCode, event.keyLocation,
+ event.ctrlKey, event.altKey, event.shiftKey);
+
+ makeCurrent();
+ _stage.dispatchEvent(keyEvent);
+
+ if (keyEvent.isDefaultPrevented())
+ event.preventDefault();
+ }
+
+ private function onResize(event:Event):void
+ {
+ var stageWidth:int = event.target.stageWidth;
+ var stageHeight:int = event.target.stageHeight;
+
+ if (contextValid)
+ dispatchResizeEvent();
+ else
+ addEventListener(Event.CONTEXT3D_CREATE, dispatchResizeEvent);
+
+ function dispatchResizeEvent():void
+ {
+ // on Android, the context is not valid while we're resizing. To avoid problems
+ // with user code, we delay the event dispatching until it becomes valid again.
+
+ makeCurrent();
+ removeEventListener(Event.CONTEXT3D_CREATE, dispatchResizeEvent);
+ _stage.dispatchEvent(new ResizeEvent(Event.RESIZE, stageWidth, stageHeight));
+ }
+ }
+
+ private function onMouseLeave(event:Event):void
+ {
+ _touchProcessor.enqueueMouseLeftStage();
+ }
+
+ private function onTouch(event:Event):void
+ {
+ if (!_started) return;
+
+ var globalX:Number;
+ var globalY:Number;
+ var touchID:int;
+ var phase:String;
+ var pressure:Number = 1.0;
+ var width:Number = 1.0;
+ var height:Number = 1.0;
+
+ // figure out general touch properties
+ if (event is MouseEvent)
+ {
+ var mouseEvent:MouseEvent = event as MouseEvent;
+ globalX = mouseEvent.stageX;
+ globalY = mouseEvent.stageY;
+ touchID = 0;
+
+ // MouseEvent.buttonDown returns true for both left and right button (AIR supports
+ // the right mouse button). We only want to react on the left button for now,
+ // so we have to save the state for the left button manually.
+ if (event.type == MouseEvent.MOUSE_DOWN) _leftMouseDown = true;
+ else if (event.type == MouseEvent.MOUSE_UP) _leftMouseDown = false;
+ }
+ else
+ {
+ var touchEvent:TouchEvent = event as TouchEvent;
+
+ // On a system that supports both mouse and touch input, the primary touch point
+ // is dispatched as mouse event as well. Since we don't want to listen to that
+ // event twice, we ignore the primary touch in that case.
+
+ if (Mouse.supportsCursor && touchEvent.isPrimaryTouchPoint) return;
+ else
+ {
+ globalX = touchEvent.stageX;
+ globalY = touchEvent.stageY;
+ touchID = touchEvent.touchPointID;
+ pressure = touchEvent.pressure;
+ width = touchEvent.sizeX;
+ height = touchEvent.sizeY;
+ }
+ }
+
+ // figure out touch phase
+ switch (event.type)
+ {
+ case TouchEvent.TOUCH_BEGIN: phase = TouchPhase.BEGAN; break;
+ case TouchEvent.TOUCH_MOVE: phase = TouchPhase.MOVED; break;
+ case TouchEvent.TOUCH_END: phase = TouchPhase.ENDED; break;
+ case MouseEvent.MOUSE_DOWN: phase = TouchPhase.BEGAN; break;
+ case MouseEvent.MOUSE_UP: phase = TouchPhase.ENDED; break;
+ case MouseEvent.MOUSE_MOVE:
+ phase = (_leftMouseDown ? TouchPhase.MOVED : TouchPhase.HOVER); break;
+ }
+
+ // move position into viewport bounds
+ globalX = _stage.stageWidth * (globalX - _viewPort.x) / _viewPort.width;
+ globalY = _stage.stageHeight * (globalY - _viewPort.y) / _viewPort.height;
+
+ // enqueue touch in touch processor
+ _touchProcessor.enqueue(touchID, phase, globalX, globalY, pressure, width, height);
+
+ // allow objects that depend on mouse-over state to be updated immediately
+ if (event.type == MouseEvent.MOUSE_UP && Mouse.supportsCursor)
+ _touchProcessor.enqueue(touchID, TouchPhase.HOVER, globalX, globalY);
+ }
+
+ private function get touchEventTypes():Array
+ {
+ var types:Array = [];
+
+ if (multitouchEnabled)
+ types.push(TouchEvent.TOUCH_BEGIN, TouchEvent.TOUCH_MOVE, TouchEvent.TOUCH_END);
+
+ if (!multitouchEnabled || Mouse.supportsCursor)
+ types.push(MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_MOVE, MouseEvent.MOUSE_UP);
+
+ return types;
+ }
+
+ private function get mustAlwaysRender():Boolean
+ {
+ // On mobile, and in some browsers with the "baselineConstrained" profile, the
+ // standard display list is only rendered after calling "context.present()".
+ // In such a case, we cannot omit frames if there is any content on the stage.
+
+ if (!_skipUnchangedFrames || _painter.shareContext)
+ return true;
+ else if (SystemUtil.isDesktop && profile != Context3DProfile.BASELINE_CONSTRAINED)
+ return false;
+ else
+ {
+ // Rendering can be skipped when both this and previous frame are empty.
+ var nativeStageEmpty:Boolean = isNativeDisplayObjectEmpty(_nativeStage);
+ var mustAlwaysRender:Boolean = !nativeStageEmpty || !_nativeStageEmpty;
+ _nativeStageEmpty = nativeStageEmpty;
+
+ return mustAlwaysRender;
+ }
+ }
+
+ // properties
+
+ /** Indicates if this Starling instance is started. */
+ public function get isStarted():Boolean { return _started; }
+
+ /** The default juggler of this instance. Will be advanced once per frame. */
+ public function get juggler():Juggler { return _juggler; }
+
+ /** The painter, which is used for all rendering. The same instance is passed to all
+ * rendermethods each frame. */
+ public function get painter():Painter { return _painter; }
+
+ /** The render context of this instance. */
+ public function get context():Context3D { return _painter.context; }
+
+ /** Indicates if multitouch simulation with "Shift" and "Ctrl"/"Cmd"-keys is enabled.
+ * @default false */
+ public function get simulateMultitouch():Boolean { return _touchProcessor.simulateMultitouch; }
+ public function set simulateMultitouch(value:Boolean):void
+ {
+ _touchProcessor.simulateMultitouch = value;
+ }
+
+ /** Indicates if Stage3D render methods will report errors. It's recommended to activate
+ * this when writing custom rendering code (shaders, etc.), since you'll get more detailed
+ * error messages. However, it has a very negative impact on performance, and it prevents
+ * ATF textures from being restored on a context loss. Never activate for release builds!
+ *
+ * @default false */
+ public function get enableErrorChecking():Boolean { return _painter.enableErrorChecking; }
+ public function set enableErrorChecking(value:Boolean):void
+ {
+ _painter.enableErrorChecking = value;
+ }
+
+ /** The anti-aliasing level. 0 - none, 16 - maximum. @default 0 */
+ public function get antiAliasing():int { return _antiAliasing; }
+ public function set antiAliasing(value:int):void
+ {
+ if (_antiAliasing != value)
+ {
+ _antiAliasing = value;
+ if (contextValid) updateViewPort(true);
+ }
+ }
+
+ /** The viewport into which Starling contents will be rendered. */
+ public function get viewPort():Rectangle { return _viewPort; }
+ public function set viewPort(value:Rectangle):void { _viewPort = value.clone(); }
+
+ /** The ratio between viewPort width and stage width. Useful for choosing a different
+ * set of textures depending on the display resolution. */
+ public function get contentScaleFactor():Number
+ {
+ return (_viewPort.width * _painter.backBufferScaleFactor) / _stage.stageWidth;
+ }
+
+ /** A Flash Sprite placed directly on top of the Starling content. Use it to display native
+ * Flash components. */
+ public function get nativeOverlay():Sprite { return _nativeOverlay; }
+
+ /** Indicates if a small statistics box (with FPS, memory usage and draw count) is
+ * displayed.
+ *
+ *
When the box turns dark green, more than 50% of the frames since the box' last
+ * update could skip rendering altogether. This will only happen if the property
+ * skipUnchangedFrames is enabled.
+ *
+ *
Beware that the memory usage should be taken with a grain of salt. The value is
+ * determined via System.totalMemory and does not take texture memory
+ * into account. It is recommended to use Adobe Scout for reliable and comprehensive
+ * memory analysis.
+ */
+ public function get showStats():Boolean { return _showStats; }
+ public function set showStats(value:Boolean):void
+ {
+ _showStats = value;
+
+ if (value)
+ {
+ if (_statsDisplay) _stage.addChild(_statsDisplay);
+ else showStatsAt();
+ }
+ else if (_statsDisplay)
+ {
+ _statsDisplay.removeFromParent();
+ }
+ }
+
+ /** Displays the statistics box at a certain position. */
+ public function showStatsAt(horizontalAlign:String="left",
+ verticalAlign:String="top", scale:Number=1):void
+ {
+ _showStats = true;
+
+ if (context == null)
+ {
+ // Starling is not yet ready - we postpone this until it's initialized.
+ addEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
+ }
+ else
+ {
+ var stageWidth:int = _stage.stageWidth;
+ var stageHeight:int = _stage.stageHeight;
+
+ if (_statsDisplay == null)
+ {
+ _statsDisplay = new StatsDisplay();
+ _statsDisplay.touchable = false;
+ }
+
+ _stage.addChild(_statsDisplay);
+ _statsDisplay.scaleX = _statsDisplay.scaleY = scale;
+
+ if (horizontalAlign == Align.LEFT) _statsDisplay.x = 0;
+ else if (horizontalAlign == Align.RIGHT) _statsDisplay.x = stageWidth - _statsDisplay.width;
+ else if (horizontalAlign == Align.CENTER) _statsDisplay.x = (stageWidth - _statsDisplay.width) / 2;
+ else throw new ArgumentError("Invalid horizontal alignment: " + horizontalAlign);
+
+ if (verticalAlign == Align.TOP) _statsDisplay.y = 0;
+ else if (verticalAlign == Align.BOTTOM) _statsDisplay.y = stageHeight - _statsDisplay.height;
+ else if (verticalAlign == Align.CENTER) _statsDisplay.y = (stageHeight - _statsDisplay.height) / 2;
+ else throw new ArgumentError("Invalid vertical alignment: " + verticalAlign);
+ }
+
+ function onRootCreated():void
+ {
+ if (_showStats) showStatsAt(horizontalAlign, verticalAlign, scale);
+ removeEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
+ }
+ }
+
+ /** The Starling stage object, which is the root of the display tree that is rendered. */
+ public function get stage():Stage { return _stage; }
+
+ /** The Flash Stage3D object Starling renders into. */
+ public function get stage3D():Stage3D { return _painter.stage3D; }
+
+ /** The Flash (2D) stage object Starling renders beneath. */
+ public function get nativeStage():flash.display.Stage { return _nativeStage; }
+
+ /** The instance of the root class provided in the constructor. Available as soon as
+ * the event 'ROOT_CREATED' has been dispatched. */
+ public function get root():DisplayObject { return _root; }
+
+ /** The class that will be instantiated by Starling as the 'root' display object.
+ * Must be a subclass of 'starling.display.DisplayObject'.
+ *
+ *
If you passed null as first parameter to the Starling constructor,
+ * you can use this property to set the root class at a later time. As soon as the class
+ * is instantiated, Starling will dispatch a ROOT_CREATED event.
+ *
+ *
Beware: you cannot change the root class once the root object has been
+ * instantiated.
+ */
+ public function get rootClass():Class { return _rootClass; }
+ public function set rootClass(value:Class):void
+ {
+ if (_rootClass != null && _root != null)
+ throw new Error("Root class may not change after root has been instantiated");
+ else if (_rootClass == null)
+ {
+ _rootClass = value;
+ if (context) initializeRoot();
+ }
+ }
+
+ /** Indicates if another Starling instance (or another Stage3D framework altogether)
+ * uses the same render context. If enabled, Starling will not execute any destructive
+ * context operations (e.g. not call 'configureBackBuffer', 'clear', 'present', etc.
+ * This has to be done manually, then. @default false */
+ public function get shareContext() : Boolean { return _painter.shareContext; }
+ public function set shareContext(value : Boolean) : void { _painter.shareContext = value; }
+
+ /** The Context3D profile of the current render context, or null
+ * if the context has not been created yet. */
+ public function get profile():String { return _painter.profile; }
+
+ /** Indicates that if the device supports HiDPI screens Starling will attempt to allocate
+ * a larger back buffer than indicated via the viewPort size. Note that this is used
+ * on Desktop only; mobile AIR apps still use the "requestedDisplayResolution" parameter
+ * the application descriptor XML. @default false */
+ public function get supportHighResolutions():Boolean { return _supportHighResolutions; }
+ public function set supportHighResolutions(value:Boolean):void
+ {
+ if (_supportHighResolutions != value)
+ {
+ _supportHighResolutions = value;
+ if (contextValid) updateViewPort(true);
+ }
+ }
+
+ /** When enabled, Starling will skip rendering the stage if it hasn't changed since the
+ * last frame. This is great for apps that remain static from time to time, since it will
+ * greatly reduce power consumption. You should activate this whenever possible!
+ *
+ *
The reason why it's disabled by default is just that it causes problems with Render-
+ * and VideoTextures. When you use those, you either have to disable this property
+ * temporarily, or call setRequiresRedraw() (ideally on the stage) whenever
+ * those textures are changing. Otherwise, the changes won't show up.
+ *
+ * @default false
+ */
+ public function get skipUnchangedFrames():Boolean { return _skipUnchangedFrames; }
+ public function set skipUnchangedFrames(value:Boolean):void
+ {
+ _skipUnchangedFrames = value;
+ _nativeStageEmpty = false; // required by 'mustAlwaysRender'
+ }
+
+ /** The TouchProcessor is passed all mouse and touch input and is responsible for
+ * dispatching TouchEvents to the Starling display tree. If you want to handle these
+ * types of input manually, pass your own custom subclass to this property. */
+ public function get touchProcessor():TouchProcessor { return _touchProcessor; }
+ public function set touchProcessor(value:TouchProcessor):void
+ {
+ if (value == null) throw new ArgumentError("TouchProcessor must not be null");
+ else if (value != _touchProcessor)
+ {
+ _touchProcessor.dispose();
+ _touchProcessor = value;
+ }
+ }
+
+ /** The number of frames that have been rendered since this instance was created. */
+ public function get frameID():uint { return _frameID; }
+
+ /** Indicates if the Context3D object is currently valid (i.e. it hasn't been lost or
+ * disposed). */
+ public function get contextValid():Boolean { return _painter.contextValid; }
+
+ // static properties
+
+ /** The currently active Starling instance. */
+ public static function get current():Starling { return sCurrent; }
+
+ /** All Starling instances.
CAUTION: not a copy, but the actual object! Do not modify!
*/
+ public static function get all():Vector. { return sAll; }
+
+ /** The render context of the currently active Starling instance. */
+ public static function get context():Context3D { return sCurrent ? sCurrent.context : null; }
+
+ /** The default juggler of the currently active Starling instance. */
+ public static function get juggler():Juggler { return sCurrent ? sCurrent._juggler : null; }
+
+ /** The painter used for all rendering of the currently active Starling instance. */
+ public static function get painter():Painter { return sCurrent ? sCurrent._painter : null; }
+
+ /** The contentScaleFactor of the currently active Starling instance. */
+ public static function get contentScaleFactor():Number
+ {
+ return sCurrent ? sCurrent.contentScaleFactor : 1.0;
+ }
+
+ /** Indicates if multitouch input should be supported. */
+ public static function get multitouchEnabled():Boolean
+ {
+ return Multitouch.inputMode == MultitouchInputMode.TOUCH_POINT;
+ }
+
+ public static function set multitouchEnabled(value:Boolean):void
+ {
+ if (sCurrent) throw new IllegalOperationError(
+ "'multitouchEnabled' must be set before Starling instance is created");
+ else
+ Multitouch.inputMode = value ? MultitouchInputMode.TOUCH_POINT :
+ MultitouchInputMode.NONE;
+ }
+
+ /** The number of frames that have been rendered since the current instance was created. */
+ public static function get frameID():uint
+ {
+ return sCurrent ? sCurrent._frameID : 0;
+ }
+ }
+}
+
+import flash.display.DisplayObject;
+import flash.display.DisplayObjectContainer;
+
+// put here to avoid naming conflicts
+function isNativeDisplayObjectEmpty(object:DisplayObject):Boolean
+{
+ if (object == null) return true;
+ else if (object is DisplayObjectContainer)
+ {
+ var container:DisplayObjectContainer = object as DisplayObjectContainer;
+ var numChildren:int = container.numChildren;
+
+ for (var i:int=0; i UPDATE_INTERVAL)
+ {
+ update();
+ _frameCount = _skipCount = _totalTime = 0;
+ }
+ }
+
+ /** Updates the displayed values. */
+ public function update():void
+ {
+ _background.color = _skipCount > _frameCount / 2 ? 0x003F00 : 0x0;
+ _fps = _totalTime > 0 ? _frameCount / _totalTime : 0;
+ _memory = System.totalMemory * B_TO_MB;
+ _gpuMemory = supportsGpuMem ? Starling.context['totalGPUMemory'] * B_TO_MB : -1;
+
+ var fpsText:String = _fps.toFixed(_fps < 100 ? 1 : 0);
+ var memText:String = _memory.toFixed(_memory < 100 ? 1 : 0);
+ var gpuMemText:String = _gpuMemory.toFixed(_gpuMemory < 100 ? 1 : 0);
+ var drwText:String = (_totalTime > 0 ? _drawCount-2 : _drawCount).toString(); // ignore self
+
+ _values.text = fpsText + "\n" + memText + "\n" +
+ (_gpuMemory >= 0 ? gpuMemText + "\n" : "") + drwText;
+ }
+
+ /** Call this once in every frame that can skip rendering because nothing changed. */
+ public function markFrameAsSkipped():void
+ {
+ _skipCount += 1;
+ }
+
+ public override function render(painter:Painter):void
+ {
+ // By calling 'finishQuadBatch' and 'excludeFromCache', we can make sure that the stats
+ // display is always rendered with exactly two draw calls. That is taken into account
+ // when showing the drawCount value (see 'ignore self' comment above)
+
+ painter.excludeFromCache(this);
+ painter.finishMeshBatch();
+ super.render(painter);
+ }
+
+ /** Indicates if the current runtime supports the 'totalGPUMemory' API. */
+ private function get supportsGpuMem():Boolean
+ {
+ return "totalGPUMemory" in Starling.context;
+ }
+
+ /** The number of Stage3D draw calls per second. */
+ public function get drawCount():int { return _drawCount; }
+ public function set drawCount(value:int):void { _drawCount = value; }
+
+ /** The current frames per second (updated twice per second). */
+ public function get fps():Number { return _fps; }
+ public function set fps(value:Number):void { _fps = value; }
+
+ /** The currently used system memory in MB. */
+ public function get memory():Number { return _memory; }
+ public function set memory(value:Number):void { _memory = value; }
+
+ /** The currently used graphics memory in MB. */
+ public function get gpuMemory():Number { return _gpuMemory; }
+ public function set gpuMemory(value:Number):void { _gpuMemory = value; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/core/starling_internal.as b/mobile_version/src/starling/core/starling_internal.as
new file mode 100644
index 00000000..2fa3be73
--- /dev/null
+++ b/mobile_version/src/starling/core/starling_internal.as
@@ -0,0 +1,22 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.core
+{
+ /**
+ * This namespace is used for undocumented APIs -- usually implementation
+ * details -- which can't be private because they need to visible
+ * to other classes.
+ *
+ * APIs in this namespace are completely unsupported and are likely to
+ * change in future versions of Starling.
+ */
+ public namespace starling_internal;
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/BlendMode.as b/mobile_version/src/starling/display/BlendMode.as
new file mode 100644
index 00000000..3794e2df
--- /dev/null
+++ b/mobile_version/src/starling/display/BlendMode.as
@@ -0,0 +1,136 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.display3D.Context3DBlendFactor;
+
+ import starling.core.Starling;
+
+ /** A class that provides constant values for visual blend mode effects.
+ *
+ *
A blend mode is always defined by two 'Context3DBlendFactor' values. A blend factor
+ * represents a particular four-value vector that is multiplied with the source or destination
+ * color in the blending formula. The blending formula is:
+ *
+ *
result = source × sourceFactor + destination × destinationFactor
+ *
+ *
In the formula, the source color is the output color of the pixel shader program. The
+ * destination color is the color that currently exists in the color buffer, as set by
+ * previous clear and draw operations.
+ *
+ *
You can add your own blend modes via BlendMode.register.
+ * To get the math right, remember that all colors in Starling use premultiplied alpha (PMA),
+ * which means that their RGB values were multiplied with the alpha value.
+ *
+ * @see flash.display3D.Context3DBlendFactor
+ */
+ public class BlendMode
+ {
+ private var _name:String;
+ private var _sourceFactor:String;
+ private var _destinationFactor:String;
+
+ private static var sBlendModes:Object;
+
+ /** Creates a new BlendMode instance. Don't call this method directly; instead,
+ * register a new blend mode using BlendMode.register. */
+ public function BlendMode(name:String, sourceFactor:String, destinationFactor:String)
+ {
+ _name = name;
+ _sourceFactor = sourceFactor;
+ _destinationFactor = destinationFactor;
+ }
+
+ /** Inherits the blend mode from this display object's parent. */
+ public static const AUTO:String = "auto";
+
+ /** Deactivates blending, i.e. disabling any transparency. */
+ public static const NONE:String = "none";
+
+ /** The display object appears in front of the background. */
+ public static const NORMAL:String = "normal";
+
+ /** Adds the values of the colors of the display object to the colors of its background. */
+ public static const ADD:String = "add";
+
+ /** Multiplies the values of the display object colors with the the background color. */
+ public static const MULTIPLY:String = "multiply";
+
+ /** Multiplies the complement (inverse) of the display object color with the complement of
+ * the background color, resulting in a bleaching effect. */
+ public static const SCREEN:String = "screen";
+
+ /** Erases the background when drawn on a RenderTexture. */
+ public static const ERASE:String = "erase";
+
+ /** When used on a RenderTexture, the drawn object will act as a mask for the current
+ * content, i.e. the source alpha overwrites the destination alpha. */
+ public static const MASK:String = "mask";
+
+ /** Draws under/below existing objects; useful especially on RenderTextures. */
+ public static const BELOW:String = "below";
+
+ // static access methods
+
+ /** Returns the blend mode with the given name.
+ * Throws an ArgumentError if the mode does not exist. */
+ public static function get(modeName:String):BlendMode
+ {
+ if (sBlendModes == null) registerDefaults();
+ if (modeName in sBlendModes) return sBlendModes[modeName];
+ else throw new ArgumentError("Blend mode not found: " + modeName);
+ }
+
+ /** Registers a blending mode under a certain name. */
+ public static function register(name:String, srcFactor:String, dstFactor:String):BlendMode
+ {
+ if (sBlendModes == null) registerDefaults();
+ var blendMode:BlendMode = new BlendMode(name, srcFactor, dstFactor);
+ sBlendModes[name] = blendMode;
+ return blendMode;
+ }
+
+ private static function registerDefaults():void
+ {
+ if (sBlendModes) return;
+
+ sBlendModes = {};
+ register("none" , Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);
+ register("normal", Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
+ register("add", Context3DBlendFactor.ONE, Context3DBlendFactor.ONE);
+ register("multiply", Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
+ register("screen", Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_COLOR);
+ register("erase", Context3DBlendFactor.ZERO, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
+ register("mask", Context3DBlendFactor.ZERO, Context3DBlendFactor.SOURCE_ALPHA);
+ register("below", Context3DBlendFactor.ONE_MINUS_DESTINATION_ALPHA, Context3DBlendFactor.DESTINATION_ALPHA);
+ }
+
+ // instance methods / properties
+
+ /** Sets the appropriate blend factors for source and destination on the current context. */
+ public function activate():void
+ {
+ Starling.context.setBlendFactors(_sourceFactor, _destinationFactor);
+ }
+
+ /** Returns the name of the blend mode. */
+ public function toString():String { return _name; }
+
+ /** The source blend factor of this blend mode. */
+ public function get sourceFactor():String { return _sourceFactor; }
+
+ /** The destination blend factor of this blend mode. */
+ public function get destinationFactor():String { return _destinationFactor; }
+
+ /** Returns the name of the blend mode. */
+ public function get name():String { return _name; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/Button.as b/mobile_version/src/starling/display/Button.as
new file mode 100644
index 00000000..54c84330
--- /dev/null
+++ b/mobile_version/src/starling/display/Button.as
@@ -0,0 +1,455 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Rectangle;
+ import flash.ui.Mouse;
+ import flash.ui.MouseCursor;
+
+ import starling.events.Event;
+ import starling.events.Touch;
+ import starling.events.TouchEvent;
+ import starling.events.TouchPhase;
+ import starling.styles.MeshStyle;
+ import starling.text.TextField;
+ import starling.text.TextFormat;
+ import starling.textures.Texture;
+
+ /** Dispatched when the user triggers the button. Bubbles. */
+ [Event(name="triggered", type="starling.events.Event")]
+
+ /** A simple button composed of an image and, optionally, text.
+ *
+ *
You can use different textures for various states of the button. If you're providing
+ * only an up state, the button is simply scaled a little when it is touched.
+ *
+ *
In addition, you can overlay text on the button. To customize the text, you can use
+ * properties equivalent to those of the TextField class. Move the text to a certain position
+ * by updating the textBounds property.
+ *
+ *
To react on touches on a button, there is special Event.TRIGGERED event.
+ * Use this event instead of normal touch events. That way, users can cancel button
+ * activation by moving the mouse/finger away from the button before releasing.
+ */
+ public class Button extends DisplayObjectContainer
+ {
+ private static const MAX_DRAG_DIST:Number = 50;
+
+ private var _upState:Texture;
+ private var _downState:Texture;
+ private var _overState:Texture;
+ private var _disabledState:Texture;
+
+ private var _contents:Sprite;
+ private var _body:Image;
+ private var _textField:TextField;
+ private var _textBounds:Rectangle;
+ private var _overlay:Sprite;
+
+ private var _scaleWhenDown:Number;
+ private var _scaleWhenOver:Number;
+ private var _alphaWhenDown:Number;
+ private var _alphaWhenDisabled:Number;
+ private var _useHandCursor:Boolean;
+ private var _enabled:Boolean;
+ private var _state:String;
+ private var _triggerBounds:Rectangle;
+
+ /** Creates a button with a set of state-textures and (optionally) some text.
+ * Any state that is left 'null' will display the up-state texture. Beware that all
+ * state textures should have the same dimensions. */
+ public function Button(upState:Texture, text:String="", downState:Texture=null,
+ overState:Texture=null, disabledState:Texture=null)
+ {
+ if (upState == null) throw new ArgumentError("Texture 'upState' cannot be null");
+
+ _upState = upState;
+ _downState = downState;
+ _overState = overState;
+ _disabledState = disabledState;
+
+ _state = ButtonState.UP;
+ _body = new Image(upState);
+ _body.pixelSnapping = true;
+ _scaleWhenDown = downState ? 1.0 : 0.9;
+ _scaleWhenOver = _alphaWhenDown = 1.0;
+ _alphaWhenDisabled = disabledState ? 1.0: 0.5;
+ _enabled = true;
+ _useHandCursor = true;
+ _textBounds = new Rectangle(0, 0, _body.width, _body.height);
+ _triggerBounds = new Rectangle();
+
+ _contents = new Sprite();
+ _contents.addChild(_body);
+ addChild(_contents);
+ addEventListener(TouchEvent.TOUCH, onTouch);
+
+ this.touchGroup = true;
+ this.text = text;
+ }
+
+ /** @inheritDoc */
+ public override function dispose():void
+ {
+ // text field might be disconnected from parent, so we have to dispose it manually
+ if (_textField)
+ _textField.dispose();
+
+ super.dispose();
+ }
+
+ /** Readjusts the dimensions of the button according to its current state texture.
+ * Call this method to synchronize button and texture size after assigning a texture
+ * with a different size. */
+ public function readjustSize():void
+ {
+ var prevWidth:Number = _body.width;
+ var prevHeight:Number = _body.height;
+
+ _body.readjustSize();
+
+ var scaleX:Number = _body.width / prevWidth;
+ var scaleY:Number = _body.height / prevHeight;
+
+ _textBounds.x *= scaleX;
+ _textBounds.y *= scaleY;
+ _textBounds.width *= scaleX;
+ _textBounds.height *= scaleY;
+
+ if (_textField) createTextField();
+ }
+
+ private function createTextField():void
+ {
+ if (_textField == null)
+ {
+ _textField = new TextField(_textBounds.width, _textBounds.height);
+ _textField.pixelSnapping = _body.pixelSnapping;
+ _textField.touchable = false;
+ _textField.autoScale = true;
+ _textField.batchable = true;
+ }
+
+ _textField.width = _textBounds.width;
+ _textField.height = _textBounds.height;
+ _textField.x = _textBounds.x;
+ _textField.y = _textBounds.y;
+ }
+
+ private function onTouch(event:TouchEvent):void
+ {
+ Mouse.cursor = (_useHandCursor && _enabled && event.interactsWith(this)) ?
+ MouseCursor.BUTTON : MouseCursor.AUTO;
+
+ var touch:Touch = event.getTouch(this);
+ var isWithinBounds:Boolean;
+
+ if (!_enabled)
+ {
+ return;
+ }
+ else if (touch == null)
+ {
+ state = ButtonState.UP;
+ }
+ else if (touch.phase == TouchPhase.HOVER)
+ {
+ state = ButtonState.OVER;
+ }
+ else if (touch.phase == TouchPhase.BEGAN && _state != ButtonState.DOWN)
+ {
+ _triggerBounds = getBounds(stage, _triggerBounds);
+ _triggerBounds.inflate(MAX_DRAG_DIST, MAX_DRAG_DIST);
+
+ state = ButtonState.DOWN;
+ }
+ else if (touch.phase == TouchPhase.MOVED)
+ {
+ isWithinBounds = _triggerBounds.contains(touch.globalX, touch.globalY);
+
+ if (_state == ButtonState.DOWN && !isWithinBounds)
+ {
+ // reset button when finger is moved too far away ...
+ state = ButtonState.UP;
+ }
+ else if (_state == ButtonState.UP && isWithinBounds)
+ {
+ // ... and reactivate when the finger moves back into the bounds.
+ state = ButtonState.DOWN;
+ }
+ }
+ else if (touch.phase == TouchPhase.ENDED && _state == ButtonState.DOWN)
+ {
+ state = ButtonState.UP;
+ if (!touch.cancelled) dispatchEventWith(Event.TRIGGERED, true);
+ }
+ }
+
+ /** The current state of the button. The corresponding strings are found
+ * in the ButtonState class. */
+ public function get state():String { return _state; }
+ public function set state(value:String):void
+ {
+ _state = value;
+ _contents.x = _contents.y = 0;
+ _contents.scaleX = _contents.scaleY = _contents.alpha = 1.0;
+
+ switch (_state)
+ {
+ case ButtonState.DOWN:
+ setStateTexture(_downState);
+ _contents.alpha = _alphaWhenDown;
+ _contents.scaleX = _contents.scaleY = _scaleWhenDown;
+ _contents.x = (1.0 - _scaleWhenDown) / 2.0 * _body.width;
+ _contents.y = (1.0 - _scaleWhenDown) / 2.0 * _body.height;
+ break;
+ case ButtonState.UP:
+ setStateTexture(_upState);
+ break;
+ case ButtonState.OVER:
+ setStateTexture(_overState);
+ _contents.scaleX = _contents.scaleY = _scaleWhenOver;
+ _contents.x = (1.0 - _scaleWhenOver) / 2.0 * _body.width;
+ _contents.y = (1.0 - _scaleWhenOver) / 2.0 * _body.height;
+ break;
+ case ButtonState.DISABLED:
+ setStateTexture(_disabledState);
+ _contents.alpha = _alphaWhenDisabled;
+ break;
+ default:
+ throw new ArgumentError("Invalid button state: " + _state);
+ }
+ }
+
+ private function setStateTexture(texture:Texture):void
+ {
+ _body.texture = texture ? texture : _upState;
+ }
+
+ /** The scale factor of the button on touch. Per default, a button without a down state
+ * texture will be made slightly smaller, while a button with a down state texture
+ * remains unscaled. */
+ public function get scaleWhenDown():Number { return _scaleWhenDown; }
+ public function set scaleWhenDown(value:Number):void { _scaleWhenDown = value; }
+
+ /** The scale factor of the button while the mouse cursor hovers over it. @default 1.0 */
+ public function get scaleWhenOver():Number { return _scaleWhenOver; }
+ public function set scaleWhenOver(value:Number):void { _scaleWhenOver = value; }
+
+ /** The alpha value of the button on touch. @default 1.0 */
+ public function get alphaWhenDown():Number { return _alphaWhenDown; }
+ public function set alphaWhenDown(value:Number):void { _alphaWhenDown = value; }
+
+ /** The alpha value of the button when it is disabled. @default 0.5 */
+ public function get alphaWhenDisabled():Number { return _alphaWhenDisabled; }
+ public function set alphaWhenDisabled(value:Number):void { _alphaWhenDisabled = value; }
+
+ /** Indicates if the button can be triggered. */
+ public function get enabled():Boolean { return _enabled; }
+ public function set enabled(value:Boolean):void
+ {
+ if (_enabled != value)
+ {
+ _enabled = value;
+ state = value ? ButtonState.UP : ButtonState.DISABLED;
+ }
+ }
+
+ /** The text that is displayed on the button. */
+ public function get text():String { return _textField ? _textField.text : ""; }
+ public function set text(value:String):void
+ {
+ if (value.length == 0)
+ {
+ if (_textField)
+ {
+ _textField.text = value;
+ _textField.removeFromParent();
+ }
+ }
+ else
+ {
+ createTextField();
+ _textField.text = value;
+
+ if (_textField.parent == null)
+ _contents.addChild(_textField);
+ }
+ }
+
+ /** The format of the button's TextField. */
+ public function get textFormat():TextFormat
+ {
+ if (_textField == null) createTextField();
+ return _textField.format;
+ }
+
+ public function set textFormat(value:TextFormat):void
+ {
+ if (_textField == null) createTextField();
+ _textField.format = value;
+ }
+
+ /** The style that is used to render the button's TextField. */
+ public function get textStyle():MeshStyle
+ {
+ if (_textField == null) createTextField();
+ return _textField.style;
+ }
+
+ public function set textStyle(value:MeshStyle):void
+ {
+ if (_textField == null) createTextField();
+ _textField.style = value;
+ }
+
+ /** The style that is used to render the Button. */
+ public function get style():MeshStyle { return _body.style; }
+ public function set style(value:MeshStyle):void { _body.style = value; }
+
+ /** The texture that is displayed when the button is not being touched. */
+ public function get upState():Texture { return _upState; }
+ public function set upState(value:Texture):void
+ {
+ if (value == null)
+ throw new ArgumentError("Texture 'upState' cannot be null");
+
+ if (_upState != value)
+ {
+ _upState = value;
+ if ( _state == ButtonState.UP ||
+ (_state == ButtonState.DISABLED && _disabledState == null) ||
+ (_state == ButtonState.DOWN && _downState == null) ||
+ (_state == ButtonState.OVER && _overState == null))
+ {
+ setStateTexture(value);
+ }
+ }
+ }
+
+ /** The texture that is displayed while the button is touched. */
+ public function get downState():Texture { return _downState; }
+ public function set downState(value:Texture):void
+ {
+ if (_downState != value)
+ {
+ _downState = value;
+ if (_state == ButtonState.DOWN) setStateTexture(value);
+ }
+ }
+
+ /** The texture that is displayed while mouse hovers over the button. */
+ public function get overState():Texture { return _overState; }
+ public function set overState(value:Texture):void
+ {
+ if (_overState != value)
+ {
+ _overState = value;
+ if (_state == ButtonState.OVER) setStateTexture(value);
+ }
+ }
+
+ /** The texture that is displayed when the button is disabled. */
+ public function get disabledState():Texture { return _disabledState; }
+ public function set disabledState(value:Texture):void
+ {
+ if (_disabledState != value)
+ {
+ _disabledState = value;
+ if (_state == ButtonState.DISABLED) setStateTexture(value);
+ }
+ }
+
+ /** The bounds of the button's TextField. Allows moving the text to a custom position.
+ * CAUTION: not a copy, but the actual object! Text will only update on re-assignment.
+ */
+ public function get textBounds():Rectangle { return _textBounds; }
+ public function set textBounds(value:Rectangle):void
+ {
+ _textBounds.copyFrom(value);
+ createTextField();
+ }
+
+ /** The color of the button's state image. Just like every image object, each pixel's
+ * color is multiplied with this value. @default white */
+ public function get color():uint { return _body.color; }
+ public function set color(value:uint):void { _body.color = value; }
+
+ /** The smoothing type used for the button's state image. */
+ public function get textureSmoothing():String { return _body.textureSmoothing; }
+ public function set textureSmoothing(value:String):void { _body.textureSmoothing = value; }
+
+ /** The overlay sprite is displayed on top of the button contents. It scales with the
+ * button when pressed. Use it to add additional objects to the button (e.g. an icon). */
+ public function get overlay():Sprite
+ {
+ if (_overlay == null)
+ _overlay = new Sprite();
+
+ _contents.addChild(_overlay); // make sure it's always on top
+ return _overlay;
+ }
+
+ /** Indicates if the mouse cursor should transform into a hand while it's over the button.
+ * @default true */
+ public override function get useHandCursor():Boolean { return _useHandCursor; }
+ public override function set useHandCursor(value:Boolean):void { _useHandCursor = value; }
+
+ /** Controls whether or not the instance snaps to the nearest pixel. This can prevent the
+ * object from looking blurry when it's not exactly aligned with the pixels of the screen.
+ * @default true */
+ public function get pixelSnapping():Boolean { return _body.pixelSnapping; }
+ public function set pixelSnapping(value:Boolean):void
+ {
+ _body.pixelSnapping = value;
+ if (_textField) _textField.pixelSnapping = value;
+ }
+
+ /** @private */
+ override public function set width(value:Number):void
+ {
+ // The Button might use a Scale9Grid ->
+ // we must update the body width/height manually for the grid to scale properly.
+
+ var newWidth:Number = value / (this.scaleX || 1.0);
+ var scale:Number = newWidth / (_body.width || 1.0);
+
+ _body.width = newWidth;
+ _textBounds.x *= scale;
+ _textBounds.width *= scale;
+
+ if (_textField) _textField.width = newWidth;
+ }
+
+ /** @private */
+ override public function set height(value:Number):void
+ {
+ var newHeight:Number = value / (this.scaleY || 1.0);
+ var scale:Number = newHeight / (_body.height || 1.0);
+
+ _body.height = newHeight;
+ _textBounds.y *= scale;
+ _textBounds.height *= scale;
+
+ if (_textField) _textField.height = newHeight;
+ }
+
+ /** The current scaling grid used for the button's state image. Use this property to create
+ * buttons that resize in a smart way, i.e. with the four corners keeping the same size
+ * and only stretching the center area.
+ *
+ * @see Image#scale9Grid
+ * @default null
+ */
+ public function get scale9Grid():Rectangle { return _body.scale9Grid; }
+ public function set scale9Grid(value:Rectangle):void { _body.scale9Grid = value; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/ButtonState.as b/mobile_version/src/starling/display/ButtonState.as
new file mode 100644
index 00000000..151b8f62
--- /dev/null
+++ b/mobile_version/src/starling/display/ButtonState.as
@@ -0,0 +1,33 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import starling.errors.AbstractClassError;
+
+ /** A class that provides constant values for the states of the Button class. */
+ public class ButtonState
+ {
+ /** @private */
+ public function ButtonState() { throw new AbstractClassError(); }
+
+ /** The button's default state. */
+ public static const UP:String = "up";
+
+ /** The button is pressed. */
+ public static const DOWN:String = "down";
+
+ /** The mouse hovers over the button. */
+ public static const OVER:String = "over";
+
+ /** The button was disabled altogether. */
+ public static const DISABLED:String = "disabled";
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/Canvas.as b/mobile_version/src/starling/display/Canvas.as
new file mode 100644
index 00000000..9e5cf299
--- /dev/null
+++ b/mobile_version/src/starling/display/Canvas.as
@@ -0,0 +1,121 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Point;
+
+ import starling.geom.Polygon;
+ import starling.rendering.IndexData;
+ import starling.rendering.VertexData;
+
+ /** A display object supporting basic vector drawing functionality. In its current state,
+ * the main use of this class is to provide a range of forms that can be used as masks.
+ */
+ public class Canvas extends DisplayObjectContainer
+ {
+ private var _polygons:Vector.;
+ private var _fillColor:uint;
+ private var _fillAlpha:Number;
+
+ /** Creates a new (empty) Canvas. Call one or more of the 'draw' methods to add content. */
+ public function Canvas()
+ {
+ _polygons = new [];
+ _fillColor = 0xffffff;
+ _fillAlpha = 1.0;
+ touchGroup = true;
+ }
+
+ /** @inheritDoc */
+ public override function dispose():void
+ {
+ _polygons.length = 0;
+ super.dispose();
+ }
+
+ /** @inheritDoc */
+ public override function hitTest(localPoint:Point):DisplayObject
+ {
+ if (!visible || !touchable || !hitTestMask(localPoint)) return null;
+
+ // we could also use the standard hit test implementation, but the polygon class can
+ // do that much more efficiently (it contains custom implementations for circles, etc).
+
+ for (var i:int = 0, len:int = _polygons.length; i < len; ++i)
+ if (_polygons[i].containsPoint(localPoint)) return this;
+
+ return null;
+ }
+
+ /** Draws a circle. */
+ public function drawCircle(x:Number, y:Number, radius:Number):void
+ {
+ appendPolygon(Polygon.createCircle(x, y, radius));
+ }
+
+ /** Draws an ellipse. */
+ public function drawEllipse(x:Number, y:Number, width:Number, height:Number):void
+ {
+ var radiusX:Number = width / 2.0;
+ var radiusY:Number = height / 2.0;
+
+ appendPolygon(Polygon.createEllipse(x + radiusX, y + radiusY, radiusX, radiusY));
+ }
+
+ /** Draws a rectangle. */
+ public function drawRectangle(x:Number, y:Number, width:Number, height:Number):void
+ {
+ appendPolygon(Polygon.createRectangle(x, y, width, height));
+ }
+
+ /** Draws an arbitrary polygon. */
+ public function drawPolygon(polygon:Polygon):void
+ {
+ appendPolygon(polygon);
+ }
+
+ /** Specifies a simple one-color fill that subsequent calls to drawing methods
+ * (such as drawCircle()) will use. */
+ public function beginFill(color:uint=0xffffff, alpha:Number=1.0):void
+ {
+ _fillColor = color;
+ _fillAlpha = alpha;
+ }
+
+ /** Resets the color to 'white' and alpha to '1'. */
+ public function endFill():void
+ {
+ _fillColor = 0xffffff;
+ _fillAlpha = 1.0;
+ }
+
+ /** Removes all existing vertices. */
+ public function clear():void
+ {
+ removeChildren(0, -1, true);
+ _polygons.length = 0;
+ }
+
+ private function appendPolygon(polygon:Polygon):void
+ {
+ var vertexData:VertexData = new VertexData();
+ var indexData:IndexData = new IndexData(polygon.numTriangles * 3);
+
+ polygon.triangulate(indexData);
+ polygon.copyToVertexData(vertexData);
+
+ vertexData.colorize("color", _fillColor, _fillAlpha);
+
+ addChild(new Mesh(vertexData, indexData));
+ _polygons[_polygons.length] = polygon;
+ }
+ }
+}
diff --git a/mobile_version/src/starling/display/DisplayObject.as b/mobile_version/src/starling/display/DisplayObject.as
new file mode 100644
index 00000000..34b1d179
--- /dev/null
+++ b/mobile_version/src/starling/display/DisplayObject.as
@@ -0,0 +1,1111 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.errors.IllegalOperationError;
+ import flash.geom.Matrix;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+ import flash.geom.Vector3D;
+ import flash.system.Capabilities;
+ import flash.ui.Mouse;
+ import flash.ui.MouseCursor;
+ import flash.utils.getQualifiedClassName;
+
+ import starling.core.Starling;
+ import starling.core.starling_internal;
+ import starling.errors.AbstractClassError;
+ import starling.errors.AbstractMethodError;
+ import starling.events.Event;
+ import starling.events.EventDispatcher;
+ import starling.events.TouchEvent;
+ import starling.filters.FragmentFilter;
+ import starling.rendering.BatchToken;
+ import starling.rendering.Painter;
+ import starling.utils.Align;
+ import starling.utils.MathUtil;
+ import starling.utils.MatrixUtil;
+
+ use namespace starling_internal;
+
+ /** Dispatched when an object is added to a parent. */
+ [Event(name="added", type="starling.events.Event")]
+
+ /** Dispatched when an object is connected to the stage (directly or indirectly). */
+ [Event(name="addedToStage", type="starling.events.Event")]
+
+ /** Dispatched when an object is removed from its parent. */
+ [Event(name="removed", type="starling.events.Event")]
+
+ /** Dispatched when an object is removed from the stage and won't be rendered any longer. */
+ [Event(name="removedFromStage", type="starling.events.Event")]
+
+ /** Dispatched once every frame on every object that is connected to the stage. */
+ [Event(name="enterFrame", type="starling.events.EnterFrameEvent")]
+
+ /** Dispatched when an object is touched. Bubbles. */
+ [Event(name="touch", type="starling.events.TouchEvent")]
+
+ /** Dispatched when a key on the keyboard is released. */
+ [Event(name="keyUp", type="starling.events.KeyboardEvent")]
+
+ /** Dispatched when a key on the keyboard is pressed. */
+ [Event(name="keyDown", type="starling.events.KeyboardEvent")]
+
+ /**
+ * The DisplayObject class is the base class for all objects that are rendered on the
+ * screen.
+ *
+ *
The Display Tree
+ *
+ *
In Starling, all displayable objects are organized in a display tree. Only objects that
+ * are part of the display tree will be displayed (rendered).
+ *
+ *
The display tree consists of leaf nodes (Image, Quad) that will be rendered directly to
+ * the screen, and of container nodes (subclasses of "DisplayObjectContainer", like "Sprite").
+ * A container is simply a display object that has child nodes - which can, again, be either
+ * leaf nodes or other containers.
+ *
+ *
At the base of the display tree, there is the Stage, which is a container, too. To create
+ * a Starling application, you create a custom Sprite subclass, and Starling will add an
+ * instance of this class to the stage.
+ *
+ *
A display object has properties that define its position in relation to its parent
+ * (x, y), as well as its rotation and scaling factors (scaleX, scaleY). Use the
+ * alpha and visible properties to make an object translucent or
+ * invisible.
+ *
+ *
Every display object may be the target of touch events. If you don't want an object to be
+ * touchable, you can disable the "touchable" property. When it's disabled, neither the object
+ * nor its children will receive any more touch events.
+ *
+ * Transforming coordinates
+ *
+ *
Within the display tree, each object has its own local coordinate system. If you rotate
+ * a container, you rotate that coordinate system - and thus all the children of the
+ * container.
+ *
+ *
Sometimes you need to know where a certain point lies relative to another coordinate
+ * system. That's the purpose of the method getTransformationMatrix. It will
+ * create a matrix that represents the transformation of a point in one coordinate system to
+ * another.
+ *
+ * Customization
+ *
+ *
DisplayObject is an abstract class, which means you cannot instantiate it directly,
+ * but have to use one of its many subclasses instead. For leaf nodes, this is typically
+ * 'Mesh' or its subclasses 'Quad' and 'Image'. To customize rendering of these objects,
+ * you can use fragment filters (via the filter-property on 'DisplayObject')
+ * or mesh styles (via the style-property on 'Mesh'). Look at the respective
+ * class documentation for more information.
+ *
+ * @see DisplayObjectContainer
+ * @see Sprite
+ * @see Stage
+ * @see Mesh
+ * @see starling.filters.FragmentFilter
+ * @see starling.styles.MeshStyle
+ */
+ public class DisplayObject extends EventDispatcher
+ {
+ // private members
+
+ private var _x:Number;
+ private var _y:Number;
+ private var _pivotX:Number;
+ private var _pivotY:Number;
+ private var _scaleX:Number;
+ private var _scaleY:Number;
+ private var _skewX:Number;
+ private var _skewY:Number;
+ private var _rotation:Number;
+ private var _alpha:Number;
+ private var _visible:Boolean;
+ private var _touchable:Boolean;
+ private var _blendMode:String;
+ private var _name:String;
+ private var _useHandCursor:Boolean;
+ private var _transformationMatrix:Matrix;
+ private var _transformationMatrix3D:Matrix3D;
+ private var _orientationChanged:Boolean;
+ private var _is3D:Boolean;
+ private var _maskee:DisplayObject;
+
+ // internal members (for fast access on rendering)
+
+ /** @private */ internal var _parent:DisplayObjectContainer;
+ /** @private */ internal var _lastParentOrSelfChangeFrameID:uint;
+ /** @private */ internal var _lastChildChangeFrameID:uint;
+ /** @private */ internal var _tokenFrameID:uint;
+ /** @private */ internal var _pushToken:BatchToken = new BatchToken();
+ /** @private */ internal var _popToken:BatchToken = new BatchToken();
+ /** @private */ internal var _hasVisibleArea:Boolean;
+ /** @private */ internal var _filter:FragmentFilter;
+ /** @private */ internal var _mask:DisplayObject;
+
+ // helper objects
+
+ private static var sAncestors:Vector. = new [];
+ private static var sHelperPoint:Point = new Point();
+ private static var sHelperPoint3D:Vector3D = new Vector3D();
+ private static var sHelperPointAlt3D:Vector3D = new Vector3D();
+ private static var sHelperRect:Rectangle = new Rectangle();
+ private static var sHelperMatrix:Matrix = new Matrix();
+ private static var sHelperMatrixAlt:Matrix = new Matrix();
+ private static var sHelperMatrix3D:Matrix3D = new Matrix3D();
+ private static var sHelperMatrixAlt3D:Matrix3D = new Matrix3D();
+
+ /** @private */
+ public function DisplayObject()
+ {
+ if (Capabilities.isDebugger &&
+ getQualifiedClassName(this) == "starling.display::DisplayObject")
+ {
+ throw new AbstractClassError();
+ }
+
+ _x = _y = _pivotX = _pivotY = _rotation = _skewX = _skewY = 0.0;
+ _scaleX = _scaleY = _alpha = 1.0;
+ _visible = _touchable = _hasVisibleArea = true;
+ _blendMode = BlendMode.AUTO;
+ _transformationMatrix = new Matrix();
+ }
+
+ /** Disposes all resources of the display object.
+ * GPU buffers are released, event listeners are removed, filters and masks are disposed. */
+ public function dispose():void
+ {
+ if (_filter) _filter.dispose();
+ if (_mask) _mask.dispose();
+ removeEventListeners();
+ mask = null; // clear 'mask._maskee', just to be sure.
+ }
+
+ /** Removes the object from its parent, if it has one, and optionally disposes it. */
+ public function removeFromParent(dispose:Boolean=false):void
+ {
+ if (_parent) _parent.removeChild(this, dispose);
+ else if (dispose) this.dispose();
+ }
+
+ /** Creates a matrix that represents the transformation from the local coordinate system
+ * to another. If you pass an out-matrix, the result will be stored in this
+ * matrix instead of creating a new object. */
+ public function getTransformationMatrix(targetSpace:DisplayObject,
+ out:Matrix=null):Matrix
+ {
+ var commonParent:DisplayObject;
+ var currentObject:DisplayObject;
+
+ if (out) out.identity();
+ else out = new Matrix();
+
+ if (targetSpace == this)
+ {
+ return out;
+ }
+ else if (targetSpace == _parent || (targetSpace == null && _parent == null))
+ {
+ out.copyFrom(transformationMatrix);
+ return out;
+ }
+ else if (targetSpace == null || targetSpace == base)
+ {
+ // targetCoordinateSpace 'null' represents the target space of the base object.
+ // -> move up from this to base
+
+ currentObject = this;
+ while (currentObject != targetSpace)
+ {
+ out.concat(currentObject.transformationMatrix);
+ currentObject = currentObject._parent;
+ }
+
+ return out;
+ }
+ else if (targetSpace._parent == this) // optimization
+ {
+ targetSpace.getTransformationMatrix(this, out);
+ out.invert();
+
+ return out;
+ }
+
+ // 1. find a common parent of this and the target space
+
+ commonParent = findCommonParent(this, targetSpace);
+
+ // 2. move up from this to common parent
+
+ currentObject = this;
+ while (currentObject != commonParent)
+ {
+ out.concat(currentObject.transformationMatrix);
+ currentObject = currentObject._parent;
+ }
+
+ if (commonParent == targetSpace)
+ return out;
+
+ // 3. now move up from target until we reach the common parent
+
+ sHelperMatrix.identity();
+ currentObject = targetSpace;
+ while (currentObject != commonParent)
+ {
+ sHelperMatrix.concat(currentObject.transformationMatrix);
+ currentObject = currentObject._parent;
+ }
+
+ // 4. now combine the two matrices
+
+ sHelperMatrix.invert();
+ out.concat(sHelperMatrix);
+
+ return out;
+ }
+
+ /** Returns a rectangle that completely encloses the object as it appears in another
+ * coordinate system. If you pass an out-rectangle, the result will be
+ * stored in this rectangle instead of creating a new object. */
+ public function getBounds(targetSpace:DisplayObject, out:Rectangle=null):Rectangle
+ {
+ throw new AbstractMethodError();
+ }
+
+ /** Returns the object that is found topmost beneath a point in local coordinates, or nil
+ * if the test fails. Untouchable and invisible objects will cause the test to fail. */
+ public function hitTest(localPoint:Point):DisplayObject
+ {
+ // on a touch test, invisible or untouchable objects cause the test to fail
+ if (!_visible || !_touchable) return null;
+
+ // if we've got a mask and the hit occurs outside, fail
+ if (_mask && !hitTestMask(localPoint)) return null;
+
+ // otherwise, check bounding box
+ if (getBounds(this, sHelperRect).containsPoint(localPoint)) return this;
+ else return null;
+ }
+
+ /** Checks if a certain point is inside the display object's mask. If there is no mask,
+ * this method always returns true (because having no mask is equivalent
+ * to having one that's infinitely big). */
+ public function hitTestMask(localPoint:Point):Boolean
+ {
+ if (_mask)
+ {
+ if (_mask.stage) getTransformationMatrix(_mask, sHelperMatrixAlt);
+ else
+ {
+ sHelperMatrixAlt.copyFrom(_mask.transformationMatrix);
+ sHelperMatrixAlt.invert();
+ }
+
+ var helperPoint:Point = localPoint == sHelperPoint ? new Point() : sHelperPoint;
+ MatrixUtil.transformPoint(sHelperMatrixAlt, localPoint, helperPoint);
+ return _mask.hitTest(helperPoint) != null;
+ }
+ else return true;
+ }
+
+ /** Transforms a point from the local coordinate system to global (stage) coordinates.
+ * If you pass an out-point, the result will be stored in this point instead
+ * of creating a new object. */
+ public function localToGlobal(localPoint:Point, out:Point=null):Point
+ {
+ if (is3D)
+ {
+ sHelperPoint3D.setTo(localPoint.x, localPoint.y, 0);
+ return local3DToGlobal(sHelperPoint3D, out);
+ }
+ else
+ {
+ getTransformationMatrix(base, sHelperMatrixAlt);
+ return MatrixUtil.transformPoint(sHelperMatrixAlt, localPoint, out);
+ }
+ }
+
+ /** Transforms a point from global (stage) coordinates to the local coordinate system.
+ * If you pass an out-point, the result will be stored in this point instead
+ * of creating a new object. */
+ public function globalToLocal(globalPoint:Point, out:Point=null):Point
+ {
+ if (is3D)
+ {
+ globalToLocal3D(globalPoint, sHelperPoint3D);
+ stage.getCameraPosition(this, sHelperPointAlt3D);
+ return MathUtil.intersectLineWithXYPlane(sHelperPointAlt3D, sHelperPoint3D, out);
+ }
+ else
+ {
+ getTransformationMatrix(base, sHelperMatrixAlt);
+ sHelperMatrixAlt.invert();
+ return MatrixUtil.transformPoint(sHelperMatrixAlt, globalPoint, out);
+ }
+ }
+
+ /** Renders the display object with the help of a painter object. Never call this method
+ * directly, except from within another render method.
+ *
+ * @param painter Captures the current render state and provides utility functions
+ * for rendering.
+ */
+ public function render(painter:Painter):void
+ {
+ throw new AbstractMethodError();
+ }
+
+ /** Moves the pivot point to a certain position within the local coordinate system
+ * of the object. If you pass no arguments, it will be centered. */
+ public function alignPivot(horizontalAlign:String="center",
+ verticalAlign:String="center"):void
+ {
+ var bounds:Rectangle = getBounds(this, sHelperRect);
+ setOrientationChanged();
+
+ if (horizontalAlign == Align.LEFT) _pivotX = bounds.x;
+ else if (horizontalAlign == Align.CENTER) _pivotX = bounds.x + bounds.width / 2.0;
+ else if (horizontalAlign == Align.RIGHT) _pivotX = bounds.x + bounds.width;
+ else throw new ArgumentError("Invalid horizontal alignment: " + horizontalAlign);
+
+ if (verticalAlign == Align.TOP) _pivotY = bounds.y;
+ else if (verticalAlign == Align.CENTER) _pivotY = bounds.y + bounds.height / 2.0;
+ else if (verticalAlign == Align.BOTTOM) _pivotY = bounds.y + bounds.height;
+ else throw new ArgumentError("Invalid vertical alignment: " + verticalAlign);
+ }
+
+ // 3D transformation
+
+ /** Creates a matrix that represents the transformation from the local coordinate system
+ * to another. This method supports three dimensional objects created via 'Sprite3D'.
+ * If you pass an out-matrix, the result will be stored in this matrix
+ * instead of creating a new object. */
+ public function getTransformationMatrix3D(targetSpace:DisplayObject,
+ out:Matrix3D=null):Matrix3D
+ {
+ var commonParent:DisplayObject;
+ var currentObject:DisplayObject;
+
+ if (out) out.identity();
+ else out = new Matrix3D();
+
+ if (targetSpace == this)
+ {
+ return out;
+ }
+ else if (targetSpace == _parent || (targetSpace == null && _parent == null))
+ {
+ out.copyFrom(transformationMatrix3D);
+ return out;
+ }
+ else if (targetSpace == null || targetSpace == base)
+ {
+ // targetCoordinateSpace 'null' represents the target space of the base object.
+ // -> move up from this to base
+
+ currentObject = this;
+ while (currentObject != targetSpace)
+ {
+ out.append(currentObject.transformationMatrix3D);
+ currentObject = currentObject._parent;
+ }
+
+ return out;
+ }
+ else if (targetSpace._parent == this) // optimization
+ {
+ targetSpace.getTransformationMatrix3D(this, out);
+ out.invert();
+
+ return out;
+ }
+
+ // 1. find a common parent of this and the target space
+
+ commonParent = findCommonParent(this, targetSpace);
+
+ // 2. move up from this to common parent
+
+ currentObject = this;
+ while (currentObject != commonParent)
+ {
+ out.append(currentObject.transformationMatrix3D);
+ currentObject = currentObject._parent;
+ }
+
+ if (commonParent == targetSpace)
+ return out;
+
+ // 3. now move up from target until we reach the common parent
+
+ sHelperMatrix3D.identity();
+ currentObject = targetSpace;
+ while (currentObject != commonParent)
+ {
+ sHelperMatrix3D.append(currentObject.transformationMatrix3D);
+ currentObject = currentObject._parent;
+ }
+
+ // 4. now combine the two matrices
+
+ sHelperMatrix3D.invert();
+ out.append(sHelperMatrix3D);
+
+ return out;
+ }
+
+ /** Transforms a 3D point from the local coordinate system to global (stage) coordinates.
+ * This is achieved by projecting the 3D point onto the (2D) view plane.
+ *
+ *
If you pass an out-point, the result will be stored in this point
+ * instead of creating a new object.
*/
+ public function local3DToGlobal(localPoint:Vector3D, out:Point=null):Point
+ {
+ var stage:Stage = this.stage;
+ if (stage == null) throw new IllegalOperationError("Object not connected to stage");
+
+ getTransformationMatrix3D(stage, sHelperMatrixAlt3D);
+ MatrixUtil.transformPoint3D(sHelperMatrixAlt3D, localPoint, sHelperPoint3D);
+ return MathUtil.intersectLineWithXYPlane(stage.cameraPosition, sHelperPoint3D, out);
+ }
+
+ /** Transforms a point from global (stage) coordinates to the 3D local coordinate system.
+ * If you pass an out-vector, the result will be stored in this vector
+ * instead of creating a new object. */
+ public function globalToLocal3D(globalPoint:Point, out:Vector3D=null):Vector3D
+ {
+ var stage:Stage = this.stage;
+ if (stage == null) throw new IllegalOperationError("Object not connected to stage");
+
+ getTransformationMatrix3D(stage, sHelperMatrixAlt3D);
+ sHelperMatrixAlt3D.invert();
+ return MatrixUtil.transformCoords3D(
+ sHelperMatrixAlt3D, globalPoint.x, globalPoint.y, 0, out);
+ }
+
+ // internal methods
+
+ /** @private */
+ starling_internal function setParent(value:DisplayObjectContainer):void
+ {
+ // check for a recursion
+ var ancestor:DisplayObject = value;
+ while (ancestor != this && ancestor != null)
+ ancestor = ancestor._parent;
+
+ if (ancestor == this)
+ throw new ArgumentError("An object cannot be added as a child to itself or one " +
+ "of its children (or children's children, etc.)");
+ else
+ _parent = value;
+ }
+
+ /** @private */
+ internal function setIs3D(value:Boolean):void
+ {
+ _is3D = value;
+ }
+
+ /** @private */
+ internal function get isMask():Boolean
+ {
+ return _maskee != null;
+ }
+
+ // render cache
+
+ /** Forces the object to be redrawn in the next frame.
+ * This will prevent the object to be drawn from the render cache.
+ *
+ *
This method is called every time the object changes in any way. When creating
+ * custom mesh styles or any other custom rendering code, call this method if the object
+ * needs to be redrawn.
+ *
+ *
If the object needs to be redrawn just because it does not support the render cache,
+ * call painter.excludeFromCache() in the object's render method instead.
+ * That way, Starling's skipUnchangedFrames policy won't be disrupted.
+ */
+ public function setRequiresRedraw():void
+ {
+ var parent:DisplayObject = _parent || _maskee;
+ var frameID:int = Starling.frameID;
+
+ _lastParentOrSelfChangeFrameID = frameID;
+ _hasVisibleArea = _alpha != 0.0 && _visible && _maskee == null &&
+ _scaleX != 0.0 && _scaleY != 0.0;
+
+ while (parent && parent._lastChildChangeFrameID != frameID)
+ {
+ parent._lastChildChangeFrameID = frameID;
+ parent = parent._parent || parent._maskee;
+ }
+ }
+
+ /** Indicates if the object needs to be redrawn in the upcoming frame, i.e. if it has
+ * changed its location relative to the stage or some other aspect of its appearance
+ * since it was last rendered. */
+ public function get requiresRedraw():Boolean
+ {
+ var frameID:uint = Starling.frameID;
+
+ return _lastParentOrSelfChangeFrameID == frameID ||
+ _lastChildChangeFrameID == frameID;
+ }
+
+ /** @private Makes sure the object is not drawn from cache in the next frame.
+ * This method is meant to be called only from Painter.finishFrame(),
+ * since it requires rendering to be concluded. */
+ starling_internal function excludeFromCache():void
+ {
+ var object:DisplayObject = this;
+ var max:uint = 0xffffffff;
+
+ while (object && object._tokenFrameID != max)
+ {
+ object._tokenFrameID = max;
+ object = object._parent;
+ }
+ }
+
+ // helpers
+
+ private function setOrientationChanged():void
+ {
+ _orientationChanged = true;
+ setRequiresRedraw();
+ }
+
+ private static function findCommonParent(object1:DisplayObject,
+ object2:DisplayObject):DisplayObject
+ {
+ var currentObject:DisplayObject = object1;
+
+ while (currentObject)
+ {
+ sAncestors[sAncestors.length] = currentObject; // avoiding 'push'
+ currentObject = currentObject._parent;
+ }
+
+ currentObject = object2;
+ while (currentObject && sAncestors.indexOf(currentObject) == -1)
+ currentObject = currentObject._parent;
+
+ sAncestors.length = 0;
+
+ if (currentObject) return currentObject;
+ else throw new ArgumentError("Object not connected to target");
+ }
+
+ // stage event handling
+
+ /** @private */
+ public override function dispatchEvent(event:Event):void
+ {
+ if (event.type == Event.REMOVED_FROM_STAGE && stage == null)
+ return; // special check to avoid double-dispatch of RfS-event.
+ else
+ super.dispatchEvent(event);
+ }
+
+ // enter frame event optimization
+
+ // To avoid looping through the complete display tree each frame to find out who's
+ // listening to ENTER_FRAME events, we manage a list of them manually in the Stage class.
+ // We need to take care that (a) it must be dispatched only when the object is
+ // part of the stage, (b) it must not cause memory leaks when the user forgets to call
+ // dispose and (c) there might be multiple listeners for this event.
+
+ /** @inheritDoc */
+ public override function addEventListener(type:String, listener:Function):void
+ {
+ if (type == Event.ENTER_FRAME && !hasEventListener(type))
+ {
+ addEventListener(Event.ADDED_TO_STAGE, addEnterFrameListenerToStage);
+ addEventListener(Event.REMOVED_FROM_STAGE, removeEnterFrameListenerFromStage);
+ if (this.stage) addEnterFrameListenerToStage();
+ }
+
+ super.addEventListener(type, listener);
+ }
+
+ /** @inheritDoc */
+ public override function removeEventListener(type:String, listener:Function):void
+ {
+ super.removeEventListener(type, listener);
+
+ if (type == Event.ENTER_FRAME && !hasEventListener(type))
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, addEnterFrameListenerToStage);
+ removeEventListener(Event.REMOVED_FROM_STAGE, removeEnterFrameListenerFromStage);
+ removeEnterFrameListenerFromStage();
+ }
+ }
+
+ /** @inheritDoc */
+ public override function removeEventListeners(type:String=null):void
+ {
+ if ((type == null || type == Event.ENTER_FRAME) && hasEventListener(Event.ENTER_FRAME))
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, addEnterFrameListenerToStage);
+ removeEventListener(Event.REMOVED_FROM_STAGE, removeEnterFrameListenerFromStage);
+ removeEnterFrameListenerFromStage();
+ }
+
+ super.removeEventListeners(type);
+ }
+
+ private function addEnterFrameListenerToStage():void
+ {
+ Starling.current.stage.addEnterFrameListener(this);
+ }
+
+ private function removeEnterFrameListenerFromStage():void
+ {
+ Starling.current.stage.removeEnterFrameListener(this);
+ }
+
+ // properties
+
+ /** The transformation matrix of the object relative to its parent.
+ *
+ *
If you assign a custom transformation matrix, Starling will try to figure out
+ * suitable values for x, y, scaleX, scaleY, and rotation.
+ * However, if the matrix was created in a different way, this might not be possible.
+ * In that case, Starling will apply the matrix, but not update the corresponding
+ * properties.
For 2D objects, this property returns just a 3D version of the 2D transformation
+ * matrix. Only the 'Sprite3D' class supports real 3D transformations.
+ *
+ *
CAUTION: not a copy, but the actual object!
*/
+ public function get transformationMatrix3D():Matrix3D
+ {
+ // this method needs to be overridden in 3D-supporting subclasses (like Sprite3D).
+
+ if (_transformationMatrix3D == null)
+ _transformationMatrix3D = new Matrix3D();
+
+ return MatrixUtil.convertTo3D(transformationMatrix, _transformationMatrix3D);
+ }
+
+ /** Indicates if this object or any of its parents is a 'Sprite3D' object. */
+ public function get is3D():Boolean { return _is3D; }
+
+ /** Indicates if the mouse cursor should transform into a hand while it's over the sprite.
+ * @default false */
+ public function get useHandCursor():Boolean { return _useHandCursor; }
+ public function set useHandCursor(value:Boolean):void
+ {
+ if (value == _useHandCursor) return;
+ _useHandCursor = value;
+
+ if (_useHandCursor)
+ addEventListener(TouchEvent.TOUCH, onTouch);
+ else
+ removeEventListener(TouchEvent.TOUCH, onTouch);
+ }
+
+ private function onTouch(event:TouchEvent):void
+ {
+ Mouse.cursor = event.interactsWith(this) ? MouseCursor.BUTTON : MouseCursor.AUTO;
+ }
+
+ /** The bounds of the object relative to the local coordinates of the parent. */
+ public function get bounds():Rectangle
+ {
+ return getBounds(_parent);
+ }
+
+ /** The width of the object in pixels.
+ * Note that for objects in a 3D space (connected to a Sprite3D), this value might not
+ * be accurate until the object is part of the display list. */
+ public function get width():Number { return getBounds(_parent, sHelperRect).width; }
+ public function set width(value:Number):void
+ {
+ // this method calls 'this.scaleX' instead of changing _scaleX directly.
+ // that way, subclasses reacting on size changes need to override only the scaleX method.
+
+ var actualWidth:Number;
+ var scaleIsNaN:Boolean = _scaleX != _scaleX; // avoid 'isNaN' call
+
+ if (_scaleX == 0.0 || scaleIsNaN) { scaleX = 1.0; actualWidth = width; }
+ else actualWidth = Math.abs(width / _scaleX);
+
+ if (actualWidth) scaleX = value / actualWidth;
+ }
+
+ /** The height of the object in pixels.
+ * Note that for objects in a 3D space (connected to a Sprite3D), this value might not
+ * be accurate until the object is part of the display list. */
+ public function get height():Number { return getBounds(_parent, sHelperRect).height; }
+ public function set height(value:Number):void
+ {
+ var actualHeight:Number;
+ var scaleIsNaN:Boolean = _scaleY != _scaleY; // avoid 'isNaN' call
+
+ if (_scaleY == 0.0 || scaleIsNaN) { scaleY = 1.0; actualHeight = height; }
+ else actualHeight = Math.abs(height / _scaleY);
+
+ if (actualHeight) scaleY = value / actualHeight;
+ }
+
+ /** The x coordinate of the object relative to the local coordinates of the parent. */
+ public function get x():Number { return _x; }
+ public function set x(value:Number):void
+ {
+ if (_x != value)
+ {
+ _x = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The y coordinate of the object relative to the local coordinates of the parent. */
+ public function get y():Number { return _y; }
+ public function set y(value:Number):void
+ {
+ if (_y != value)
+ {
+ _y = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The x coordinate of the object's origin in its own coordinate space (default: 0). */
+ public function get pivotX():Number { return _pivotX; }
+ public function set pivotX(value:Number):void
+ {
+ if (_pivotX != value)
+ {
+ _pivotX = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The y coordinate of the object's origin in its own coordinate space (default: 0). */
+ public function get pivotY():Number { return _pivotY; }
+ public function set pivotY(value:Number):void
+ {
+ if (_pivotY != value)
+ {
+ _pivotY = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The horizontal scale factor. '1' means no scale, negative values flip the object.
+ * @default 1 */
+ public function get scaleX():Number { return _scaleX; }
+ public function set scaleX(value:Number):void
+ {
+ if (_scaleX != value)
+ {
+ _scaleX = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The vertical scale factor. '1' means no scale, negative values flip the object.
+ * @default 1 */
+ public function get scaleY():Number { return _scaleY; }
+ public function set scaleY(value:Number):void
+ {
+ if (_scaleY != value)
+ {
+ _scaleY = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** Sets both 'scaleX' and 'scaleY' to the same value. The getter simply returns the
+ * value of 'scaleX' (even if the scaling values are different). @default 1 */
+ public function get scale():Number { return scaleX; }
+ public function set scale(value:Number):void { scaleX = scaleY = value; }
+
+ /** The horizontal skew angle in radians. */
+ public function get skewX():Number { return _skewX; }
+ public function set skewX(value:Number):void
+ {
+ value = MathUtil.normalizeAngle(value);
+
+ if (_skewX != value)
+ {
+ _skewX = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The vertical skew angle in radians. */
+ public function get skewY():Number { return _skewY; }
+ public function set skewY(value:Number):void
+ {
+ value = MathUtil.normalizeAngle(value);
+
+ if (_skewY != value)
+ {
+ _skewY = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** The rotation of the object in radians. (In Starling, all angles are measured
+ * in radians.) */
+ public function get rotation():Number { return _rotation; }
+ public function set rotation(value:Number):void
+ {
+ value = MathUtil.normalizeAngle(value);
+
+ if (_rotation != value)
+ {
+ _rotation = value;
+ setOrientationChanged();
+ }
+ }
+
+ /** @private Indicates if the object is rotated or skewed in any way. */
+ internal function get isRotated():Boolean
+ {
+ return _rotation != 0.0 || _skewX != 0.0 || _skewY != 0.0;
+ }
+
+ /** The opacity of the object. 0 = transparent, 1 = opaque. @default 1 */
+ public function get alpha():Number { return _alpha; }
+ public function set alpha(value:Number):void
+ {
+ if (value != _alpha)
+ {
+ _alpha = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value);
+ setRequiresRedraw();
+ }
+ }
+
+ /** The visibility of the object. An invisible object will be untouchable. */
+ public function get visible():Boolean { return _visible; }
+ public function set visible(value:Boolean):void
+ {
+ if (value != _visible)
+ {
+ _visible = value;
+ setRequiresRedraw();
+ }
+ }
+
+ /** Indicates if this object (and its children) will receive touch events. */
+ public function get touchable():Boolean { return _touchable; }
+ public function set touchable(value:Boolean):void { _touchable = value; }
+
+ /** The blend mode determines how the object is blended with the objects underneath.
+ * @default auto
+ * @see starling.display.BlendMode */
+ public function get blendMode():String { return _blendMode; }
+ public function set blendMode(value:String):void
+ {
+ if (value != _blendMode)
+ {
+ _blendMode = value;
+ setRequiresRedraw();
+ }
+ }
+
+ /** The name of the display object (default: null). Used by 'getChildByName()' of
+ * display object containers. */
+ public function get name():String { return _name; }
+ public function set name(value:String):void { _name = value; }
+
+ /** The filter that is attached to the display object. The starling.filters
+ * package contains several classes that define specific filters you can use. To combine
+ * several filters, assign an instance of the FilterChain class; to remove
+ * all filters, assign null.
+ *
+ *
Beware that a filter instance may only be used on one object at a time! Furthermore,
+ * when you remove or replace a filter, it is NOT disposed automatically (since you might
+ * want to reuse it on a different object).
+ *
+ * @default null
+ * @see starling.filters.FragmentFilter
+ * @see starling.filters.FilterChain
+ */
+ public function get filter():FragmentFilter { return _filter; }
+ public function set filter(value:FragmentFilter):void
+ {
+ if (value != _filter)
+ {
+ if (_filter) _filter.setTarget(null);
+ if (value) value.setTarget(this);
+
+ _filter = value;
+ setRequiresRedraw();
+ }
+ }
+
+ /** The display object that acts as a mask for the current object.
+ * Assign null to remove it.
+ *
+ *
A pixel of the masked display object will only be drawn if it is within one of the
+ * mask's polygons. Texture pixels and alpha values of the mask are not taken into
+ * account. The mask object itself is never visible.
+ *
+ *
If the mask is part of the display list, masking will occur at exactly the
+ * location it occupies on the stage. If it is not, the mask will be placed in the local
+ * coordinate system of the target object (as if it was one of its children).
+ *
+ *
For rectangular masks, you can use simple quads; for other forms (like circles
+ * or arbitrary shapes) it is recommended to use a 'Canvas' instance.
+ *
+ *
Beware that a mask will typically cause at least two additional draw calls:
+ * one to draw the mask to the stencil buffer and one to erase it. However, if the
+ * mask object is an instance of starling.display.Quad and is aligned
+ * parallel to the stage axes, rendering will be optimized: instead of using the
+ * stencil buffer, the object will be clipped using the scissor rectangle. That's
+ * faster and reduces the number of draw calls, so make use of this when possible.
+ *
+ * @see Canvas
+ * @default null
+ */
+ public function get mask():DisplayObject { return _mask; }
+ public function set mask(value:DisplayObject):void
+ {
+ if (_mask != value)
+ {
+ if (_mask) _mask._maskee = null;
+ if (value)
+ {
+ value._maskee = this;
+ value._hasVisibleArea = false;
+ }
+
+ _mask = value;
+ setRequiresRedraw();
+ }
+ }
+
+ /** The display object container that contains this display object. */
+ public function get parent():DisplayObjectContainer { return _parent; }
+
+ /** The topmost object in the display tree the object is part of. */
+ public function get base():DisplayObject
+ {
+ var currentObject:DisplayObject = this;
+ while (currentObject._parent) currentObject = currentObject._parent;
+ return currentObject;
+ }
+
+ /** The root object the display object is connected to (i.e. an instance of the class
+ * that was passed to the Starling constructor), or null if the object is not connected
+ * to the stage. */
+ public function get root():DisplayObject
+ {
+ var currentObject:DisplayObject = this;
+ while (currentObject._parent)
+ {
+ if (currentObject._parent is Stage) return currentObject;
+ else currentObject = currentObject.parent;
+ }
+
+ return null;
+ }
+
+ /** The stage the display object is connected to, or null if it is not connected
+ * to the stage. */
+ public function get stage():Stage { return this.base as Stage; }
+ }
+}
diff --git a/mobile_version/src/starling/display/DisplayObjectContainer.as b/mobile_version/src/starling/display/DisplayObjectContainer.as
new file mode 100644
index 00000000..c3962bca
--- /dev/null
+++ b/mobile_version/src/starling/display/DisplayObjectContainer.as
@@ -0,0 +1,508 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Matrix;
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+ import flash.system.Capabilities;
+ import flash.utils.getQualifiedClassName;
+
+ import starling.core.starling_internal;
+ import starling.errors.AbstractClassError;
+ import starling.events.Event;
+ import starling.filters.FragmentFilter;
+ import starling.rendering.BatchToken;
+ import starling.rendering.Painter;
+ import starling.utils.MatrixUtil;
+
+ use namespace starling_internal;
+
+ /**
+ * A DisplayObjectContainer represents a collection of display objects.
+ * It is the base class of all display objects that act as a container for other objects. By
+ * maintaining an ordered list of children, it defines the back-to-front positioning of the
+ * children within the display tree.
+ *
+ *
A container does not a have size in itself. The width and height properties represent the
+ * extents of its children. Changing those properties will scale all children accordingly.
+ *
+ *
As this is an abstract class, you can't instantiate it directly, but have to
+ * use a subclass instead. The most lightweight container class is "Sprite".
+ *
+ * Adding and removing children
+ *
+ *
The class defines methods that allow you to add or remove children. When you add a child,
+ * it will be added at the frontmost position, possibly occluding a child that was added
+ * before. You can access the children via an index. The first child will have index 0, the
+ * second child index 1, etc.
+ *
+ * Adding and removing objects from a container triggers non-bubbling events.
+ *
+ *
+ *
Event.ADDED: the object was added to a parent.
+ *
Event.ADDED_TO_STAGE: the object was added to a parent that is
+ * connected to the stage, thus becoming visible now.
+ *
Event.REMOVED: the object was removed from a parent.
+ *
Event.REMOVED_FROM_STAGE: the object was removed from a parent that
+ * is connected to the stage, thus becoming invisible now.
+ *
+ *
+ * Especially the ADDED_TO_STAGE event is very helpful, as it allows you to
+ * automatically execute some logic (e.g. start an animation) when an object is rendered the
+ * first time.
+ *
+ * @see Sprite
+ * @see DisplayObject
+ */
+ public class DisplayObjectContainer extends DisplayObject
+ {
+ // members
+
+ private var _children:Vector.;
+ private var _touchGroup:Boolean;
+
+ // helper objects
+ private static var sHelperMatrix:Matrix = new Matrix();
+ private static var sHelperPoint:Point = new Point();
+ private static var sBroadcastListeners:Vector. = new [];
+ private static var sSortBuffer:Vector. = new [];
+ private static var sCacheToken:BatchToken = new BatchToken();
+
+ // construction
+
+ /** @private */
+ public function DisplayObjectContainer()
+ {
+ if (Capabilities.isDebugger &&
+ getQualifiedClassName(this) == "starling.display::DisplayObjectContainer")
+ {
+ throw new AbstractClassError();
+ }
+
+ _children = new [];
+ }
+
+ /** Disposes the resources of all children. */
+ public override function dispose():void
+ {
+ for (var i:int=_children.length-1; i>=0; --i)
+ _children[i].dispose();
+
+ super.dispose();
+ }
+
+ // child management
+
+ /** Adds a child to the container. It will be at the frontmost position. */
+ public function addChild(child:DisplayObject):DisplayObject
+ {
+ return addChildAt(child, _children.length);
+ }
+
+ /** Adds a child to the container at a certain index. */
+ public function addChildAt(child:DisplayObject, index:int):DisplayObject
+ {
+ var numChildren:int = _children.length;
+
+ if (index >= 0 && index <= numChildren)
+ {
+ setRequiresRedraw();
+
+ if (child.parent == this)
+ {
+ setChildIndex(child, index); // avoids dispatching events
+ }
+ else
+ {
+ _children.insertAt(index, child);
+
+ child.removeFromParent();
+ child.setParent(this);
+ child.dispatchEventWith(Event.ADDED, true);
+
+ if (stage)
+ {
+ var container:DisplayObjectContainer = child as DisplayObjectContainer;
+ if (container) container.broadcastEventWith(Event.ADDED_TO_STAGE);
+ else child.dispatchEventWith(Event.ADDED_TO_STAGE);
+ }
+ }
+
+ return child;
+ }
+ else
+ {
+ throw new RangeError("Invalid child index");
+ }
+ }
+
+ /** Removes a child from the container. If the object is not a child, the method returns
+ * null. If requested, the child will be disposed right away. */
+ public function removeChild(child:DisplayObject, dispose:Boolean=false):DisplayObject
+ {
+ var childIndex:int = getChildIndex(child);
+ if (childIndex != -1) return removeChildAt(childIndex, dispose);
+ else return null;
+ }
+
+ /** Removes a child at a certain index. The index positions of any display objects above
+ * the child are decreased by 1. If requested, the child will be disposed right away. */
+ public function removeChildAt(index:int, dispose:Boolean=false):DisplayObject
+ {
+ if (index >= 0 && index < _children.length)
+ {
+ setRequiresRedraw();
+
+ var child:DisplayObject = _children[index];
+ child.dispatchEventWith(Event.REMOVED, true);
+
+ if (stage)
+ {
+ var container:DisplayObjectContainer = child as DisplayObjectContainer;
+ if (container) container.broadcastEventWith(Event.REMOVED_FROM_STAGE);
+ else child.dispatchEventWith(Event.REMOVED_FROM_STAGE);
+ }
+
+ child.setParent(null);
+ index = _children.indexOf(child); // index might have changed by event handler
+ if (index >= 0) _children.removeAt(index);
+ if (dispose) child.dispose();
+
+ return child;
+ }
+ else
+ {
+ throw new RangeError("Invalid child index");
+ }
+ }
+
+ /** Removes a range of children from the container (endIndex included).
+ * If no arguments are given, all children will be removed. */
+ public function removeChildren(beginIndex:int=0, endIndex:int=-1, dispose:Boolean=false):void
+ {
+ if (endIndex < 0 || endIndex >= numChildren)
+ endIndex = numChildren - 1;
+
+ for (var i:int=beginIndex; i<=endIndex; ++i)
+ removeChildAt(beginIndex, dispose);
+ }
+
+ /** Returns a child object at a certain index. If you pass a negative index,
+ * '-1' will return the last child, '-2' the second to last child, etc. */
+ public function getChildAt(index:int):DisplayObject
+ {
+ var numChildren:int = _children.length;
+
+ if (index < 0)
+ index = numChildren + index;
+
+ if (index >= 0 && index < numChildren)
+ return _children[index];
+ else
+ throw new RangeError("Invalid child index");
+ }
+
+ /** Returns a child object with a certain name (non-recursively). */
+ public function getChildByName(name:String):DisplayObject
+ {
+ var numChildren:int = _children.length;
+ for (var i:int=0; i out.x) minX = out.x;
+ if (maxX < out.right) maxX = out.right;
+ if (minY > out.y) minY = out.y;
+ if (maxY < out.bottom) maxY = out.bottom;
+ }
+
+ out.setTo(minX, minY, maxX - minX, maxY - minY);
+ }
+
+ return out;
+ }
+
+ /** @inheritDoc */
+ public override function hitTest(localPoint:Point):DisplayObject
+ {
+ if (!visible || !touchable || !hitTestMask(localPoint)) return null;
+
+ var target:DisplayObject = null;
+ var localX:Number = localPoint.x;
+ var localY:Number = localPoint.y;
+ var numChildren:int = _children.length;
+
+ for (var i:int = numChildren - 1; i >= 0; --i) // front to back!
+ {
+ var child:DisplayObject = _children[i];
+ if (child.isMask) continue;
+
+ sHelperMatrix.copyFrom(child.transformationMatrix);
+ sHelperMatrix.invert();
+
+ MatrixUtil.transformCoords(sHelperMatrix, localX, localY, sHelperPoint);
+ target = child.hitTest(sHelperPoint);
+
+ if (target) return _touchGroup ? this : target;
+ }
+
+ return null;
+ }
+
+ /** @inheritDoc */
+ public override function render(painter:Painter):void
+ {
+ var numChildren:int = _children.length;
+ var frameID:uint = painter.frameID;
+ var cacheEnabled:Boolean = frameID !=0;
+ var selfOrParentChanged:Boolean = _lastParentOrSelfChangeFrameID == frameID;
+
+ for (var i:int=0; i, compareFunc:Function,
+ startIndex:int, length:int,
+ buffer:Vector.):void
+ {
+ // This is a port of the C++ merge sort algorithm shown here:
+ // http://www.cprogramming.com/tutorial/computersciencetheory/mergesort.html
+
+ if (length > 1)
+ {
+ var i:int;
+ var endIndex:int = startIndex + length;
+ var halfLength:int = length / 2;
+ var l:int = startIndex; // current position in the left subvector
+ var r:int = startIndex + halfLength; // current position in the right subvector
+
+ // sort each subvector
+ mergeSort(input, compareFunc, startIndex, halfLength, buffer);
+ mergeSort(input, compareFunc, startIndex + halfLength, length - halfLength, buffer);
+
+ // merge the vectors, using the buffer vector for temporary storage
+ for (i = 0; i < length; i++)
+ {
+ // Check to see if any elements remain in the left vector;
+ // if so, we check if there are any elements left in the right vector;
+ // if so, we compare them. Otherwise, we know that the merge must
+ // take the element from the left vector. */
+ if (l < startIndex + halfLength &&
+ (r == endIndex || compareFunc(input[l], input[r]) <= 0))
+ {
+ buffer[i] = input[l];
+ l++;
+ }
+ else
+ {
+ buffer[i] = input[r];
+ r++;
+ }
+ }
+
+ // copy the sorted subvector back to the input
+ for(i = startIndex; i < endIndex; i++)
+ input[i] = buffer[int(i - startIndex)];
+ }
+ }
+
+ /** @private */
+ internal function getChildEventListeners(object:DisplayObject, eventType:String,
+ listeners:Vector.):void
+ {
+ var container:DisplayObjectContainer = object as DisplayObjectContainer;
+
+ if (object.hasEventListener(eventType))
+ listeners[listeners.length] = object; // avoiding 'push'
+
+ if (container)
+ {
+ var children:Vector. = container._children;
+ var numChildren:int = children.length;
+
+ for (var i:int=0; iTypically, the Image class will act as an equivalent of Flash's Bitmap class. Instead
+ * of BitmapData, Starling uses textures to represent the pixels of an image. To display a
+ * texture, you have to map it onto a quad - and that's what the Image class is for.
+ *
+ *
While the base class Quad already supports textures, the Image
+ * class adds some additional functionality.
+ *
+ *
First of all, it provides a convenient constructor that will automatically synchronize
+ * the size of the image with the displayed texture.
+ *
+ *
Furthermore, it adds support for a "Scale9" grid. This splits up the image into
+ * nine regions, the corners of which will always maintain their original size.
+ * The center region stretches in both directions to fill the remaining space; the side
+ * regions will stretch accordingly in either horizontal or vertical direction.
+ *
+ *
Finally, you can repeat a texture horizontally and vertically within the image's region,
+ * just like the tiles of a wallpaper. Use the tileGrid property to do that.
+ *
+ * @see starling.textures.Texture
+ * @see Quad
+ */
+ public class Image extends Quad
+ {
+ private var _scale9Grid:Rectangle;
+ private var _tileGrid:Rectangle;
+
+ // helper objects
+ private static var sPadding:Padding = new Padding();
+ private static var sBounds:Rectangle = new Rectangle();
+ private static var sBasCols:Vector. = new Vector.(3, true);
+ private static var sBasRows:Vector. = new Vector.(3, true);
+ private static var sPosCols:Vector. = new Vector.(3, true);
+ private static var sPosRows:Vector. = new Vector.(3, true);
+ private static var sTexCols:Vector. = new Vector.(3, true);
+ private static var sTexRows:Vector. = new Vector.(3, true);
+
+ /** Creates an image with a texture mapped onto it. */
+ public function Image(texture:Texture)
+ {
+ super(100, 100);
+ this.texture = texture;
+ readjustSize();
+ }
+
+ /** The current scaling grid that is in effect. If set to null, the image is scaled just
+ * like any other display object; assigning a rectangle will divide the image into a grid
+ * of nine regions, based on the center rectangle. The four corners of this grid will
+ * always maintain their original size; the other regions will stretch (horizontally,
+ * vertically, or both) to fill the complete area.
+ *
+ *
Notes:
+ *
+ *
+ *
Assigning a Scale9 rectangle will change the number of vertices to a maximum of 16
+ * (less if possible) and all vertices will be colored like vertex 0 (the top left vertex).
+ *
+ *
For Scale3-grid behavior, assign a zero size for all but the center row / column.
+ * This will cause the 'caps' to scale in a way that leaves the aspect ratio intact.
+ *
An image can have either a scale9Grid or a tileGrid, but
+ * not both. Assigning one will delete the other.
+ *
Changes will only be applied on assignment. To force an update, simply call
+ * image.scale9Grid = image.scale9Grid.
+ *
Assignment causes an implicit call to readjustSize(),
+ * and the same will happen when the texture is changed afterwards.
+ *
+ *
+ * @default null
+ */
+ public function get scale9Grid():Rectangle { return _scale9Grid; }
+ public function set scale9Grid(value:Rectangle):void
+ {
+ if (value)
+ {
+ if (_scale9Grid == null) _scale9Grid = value.clone();
+ else _scale9Grid.copyFrom(value);
+
+ readjustSize();
+ _tileGrid = null;
+ }
+ else _scale9Grid = null;
+
+ setupVertices();
+ }
+
+ /** The current tiling grid that is in effect. If set to null, the image is scaled just
+ * like any other display object; assigning a rectangle will divide the image into a grid
+ * displaying the current texture in each and every cell. The assigned rectangle points
+ * to the bounds of one cell; all other elements will be calculated accordingly. A zero
+ * or negative value for the rectangle's width or height will be replaced with the actual
+ * texture size. Thus, you can make a 2x2 grid simply like this:
+ *
+ *
+ * var image:Image = new Image(texture);
+ * image.tileGrid = new Rectangle();
+ * image.scale = 2;
+ *
+ *
Notes:
+ *
+ *
+ *
Assigning a tile rectangle will change the number of vertices to whatever is
+ * required by the grid. New vertices will be colored just like vertex 0 (the top left
+ * vertex).
+ *
An image can have either a scale9Grid or a tileGrid, but
+ * not both. Assigning one will delete the other.
+ *
Changes will only be applied on assignment. To force an update, simply call
+ * image.tileGrid = image.tileGrid.
+ *
+ *
+ * @default null
+ */
+ public function get tileGrid():Rectangle { return _tileGrid; }
+ public function set tileGrid(value:Rectangle):void
+ {
+ if (value)
+ {
+ if (_tileGrid == null) _tileGrid = value.clone();
+ else _tileGrid.copyFrom(value);
+
+ _scale9Grid = null;
+ }
+ else _tileGrid = null;
+
+ setupVertices();
+ }
+
+ /** @private */
+ override protected function setupVertices():void
+ {
+ if (texture && _scale9Grid) setupScale9Grid();
+ else if (texture && _tileGrid) setupTileGrid();
+ else super.setupVertices();
+ }
+
+ /** @private */
+ override public function set scaleX(value:Number):void
+ {
+ super.scaleX = value;
+ if (texture && (_scale9Grid || _tileGrid)) setupVertices();
+ }
+
+ /** @private */
+ override public function set scaleY(value:Number):void
+ {
+ super.scaleY = value;
+ if (texture && (_scale9Grid || _tileGrid)) setupVertices();
+ }
+
+ /** @private */
+ override public function set texture(value:Texture):void
+ {
+ if (value != texture)
+ {
+ super.texture = value;
+ if (_scale9Grid && value) readjustSize();
+ }
+ }
+
+ // vertex setup
+
+ private function setupScale9Grid():void
+ {
+ var texture:Texture = this.texture;
+ var frame:Rectangle = texture.frame;
+ var absScaleX:Number = scaleX > 0 ? scaleX : -scaleX;
+ var absScaleY:Number = scaleY > 0 ? scaleY : -scaleY;
+
+ // If top and bottom row / left and right column are empty, this is actually
+ // a scale3 grid. In that case, we want the 'caps' to maintain their aspect ratio.
+
+ if (MathUtil.isEquivalent(_scale9Grid.width, texture.frameWidth))
+ absScaleY /= absScaleX;
+ else if (MathUtil.isEquivalent(_scale9Grid.height, texture.frameHeight))
+ absScaleX /= absScaleY;
+
+ var invScaleX:Number = 1.0 / absScaleX;
+ var invScaleY:Number = 1.0 / absScaleY;
+ var vertexData:VertexData = this.vertexData;
+ var indexData:IndexData = this.indexData;
+ var prevNumVertices:int = vertexData.numVertices;
+ var numVertices:int, numQuads:int;
+ var correction:Number;
+
+ // The following rectangles are used to figure everything out.
+ // The meaning of each is depicted in this sketch: http://i.imgur.com/KUcv71O.jpg
+
+ var gridCenter:Rectangle = Pool.getRectangle();
+ var textureBounds:Rectangle = Pool.getRectangle();
+ var pixelBounds:Rectangle = Pool.getRectangle();
+ var intersection:Rectangle = Pool.getRectangle();
+
+ gridCenter.copyFrom(_scale9Grid);
+ textureBounds.setTo(0, 0, texture.frameWidth, texture.frameHeight);
+
+ if (frame) pixelBounds.setTo(-frame.x, -frame.y, texture.width, texture.height);
+ else pixelBounds.copyFrom(textureBounds);
+
+ // calculate 3x3 grid according to texture and scale9 properties,
+ // taking special care about the texture frame (headache included)
+
+ RectangleUtil.intersect(gridCenter, pixelBounds, intersection);
+
+ sBasCols[0] = sBasCols[2] = 0;
+ sBasRows[0] = sBasRows[2] = 0;
+ sBasCols[1] = intersection.width;
+ sBasRows[1] = intersection.height;
+
+ if (pixelBounds.x < gridCenter.x)
+ sBasCols[0] = gridCenter.x - pixelBounds.x;
+
+ if (pixelBounds.y < gridCenter.y)
+ sBasRows[0] = gridCenter.y - pixelBounds.y;
+
+ if (pixelBounds.right > gridCenter.right)
+ sBasCols[2] = pixelBounds.right - gridCenter.right;
+
+ if (pixelBounds.bottom > gridCenter.bottom)
+ sBasRows[2] = pixelBounds.bottom - gridCenter.bottom;
+
+ // set vertex positions
+
+ if (pixelBounds.x < gridCenter.x)
+ sPadding.left = pixelBounds.x * invScaleX;
+ else
+ sPadding.left = gridCenter.x * invScaleX + pixelBounds.x - gridCenter.x;
+
+ if (pixelBounds.right > gridCenter.right)
+ sPadding.right = (textureBounds.width - pixelBounds.right) * invScaleX;
+ else
+ sPadding.right = (textureBounds.width - gridCenter.right) * invScaleX + gridCenter.right - pixelBounds.right;
+
+ if (pixelBounds.y < gridCenter.y)
+ sPadding.top = pixelBounds.y * invScaleY;
+ else
+ sPadding.top = gridCenter.y * invScaleY + pixelBounds.y - gridCenter.y;
+
+ if (pixelBounds.bottom > gridCenter.bottom)
+ sPadding.bottom = (textureBounds.height - pixelBounds.bottom) * invScaleY;
+ else
+ sPadding.bottom = (textureBounds.height - gridCenter.bottom) * invScaleY + gridCenter.bottom - pixelBounds.bottom;
+
+ sPosCols[0] = sBasCols[0] * invScaleX;
+ sPosCols[2] = sBasCols[2] * invScaleX;
+ sPosCols[1] = textureBounds.width - sPadding.left - sPadding.right - sPosCols[0] - sPosCols[2];
+
+ sPosRows[0] = sBasRows[0] * invScaleY;
+ sPosRows[2] = sBasRows[2] * invScaleY;
+ sPosRows[1] = textureBounds.height - sPadding.top - sPadding.bottom - sPosRows[0] - sPosRows[2];
+
+ // if the total width / height becomes smaller than the outer columns / rows,
+ // we hide the center column / row and scale the rest normally.
+
+ if (sPosCols[1] <= 0)
+ {
+ correction = textureBounds.width / (textureBounds.width - gridCenter.width) * absScaleX;
+ sPadding.left *= correction;
+ sPosCols[0] *= correction;
+ sPosCols[1] = 0.0;
+ sPosCols[2] *= correction;
+ }
+
+ if (sPosRows[1] <= 0)
+ {
+ correction = textureBounds.height / (textureBounds.height - gridCenter.height) * absScaleY;
+ sPadding.top *= correction;
+ sPosRows[0] *= correction;
+ sPosRows[1] = 0.0;
+ sPosRows[2] *= correction;
+ }
+
+ // now set the texture coordinates
+
+ sTexCols[0] = sBasCols[0] / pixelBounds.width;
+ sTexCols[2] = sBasCols[2] / pixelBounds.width;
+ sTexCols[1] = 1.0 - sTexCols[0] - sTexCols[2];
+
+ sTexRows[0] = sBasRows[0] / pixelBounds.height;
+ sTexRows[2] = sBasRows[2] / pixelBounds.height;
+ sTexRows[1] = 1.0 - sTexRows[0] - sTexRows[2];
+
+ numVertices = setupScale9GridAttributes(
+ sPadding.left, sPadding.top, sPosCols, sPosRows, sTexCols, sTexRows);
+
+ // update indices
+
+ numQuads = numVertices / 4;
+ vertexData.numVertices = numVertices;
+ indexData.numIndices = 0;
+
+ for (var i:int=0; i, posRows:Vector.,
+ texCols:Vector., texRows:Vector.):int
+ {
+ const posAttr:String = "position";
+ const texAttr:String = "texCoords";
+
+ var row:int, col:int;
+ var colWidthPos:Number, rowHeightPos:Number;
+ var colWidthTex:Number, rowHeightTex:Number;
+ var vertexData:VertexData = this.vertexData;
+ var texture:Texture = this.texture;
+ var currentX:Number = startX;
+ var currentY:Number = startY;
+ var currentU:Number = 0.0;
+ var currentV:Number = 0.0;
+ var vertexID:int = 0;
+
+ for (row = 0; row < 3; ++row)
+ {
+ rowHeightPos = posRows[row];
+ rowHeightTex = texRows[row];
+
+ if (rowHeightPos > 0)
+ {
+ for (col = 0; col < 3; ++col)
+ {
+ colWidthPos = posCols[col];
+ colWidthTex = texCols[col];
+
+ if (colWidthPos > 0)
+ {
+ vertexData.setPoint(vertexID, posAttr, currentX, currentY);
+ texture.setTexCoords(vertexData, vertexID, texAttr, currentU, currentV);
+ vertexID++;
+
+ vertexData.setPoint(vertexID, posAttr, currentX + colWidthPos, currentY);
+ texture.setTexCoords(vertexData, vertexID, texAttr, currentU + colWidthTex, currentV);
+ vertexID++;
+
+ vertexData.setPoint(vertexID, posAttr, currentX, currentY + rowHeightPos);
+ texture.setTexCoords(vertexData, vertexID, texAttr, currentU, currentV + rowHeightTex);
+ vertexID++;
+
+ vertexData.setPoint(vertexID, posAttr, currentX + colWidthPos, currentY + rowHeightPos);
+ texture.setTexCoords(vertexData, vertexID, texAttr, currentU + colWidthTex, currentV + rowHeightTex);
+ vertexID++;
+
+ currentX += colWidthPos;
+ }
+
+ currentU += colWidthTex;
+ }
+
+ currentY += rowHeightPos;
+ }
+
+ currentX = startX;
+ currentU = 0.0;
+ currentV += rowHeightTex;
+ }
+
+ return vertexID;
+ }
+
+ private function setupTileGrid():void
+ {
+ // calculate the grid of vertices simulating a repeating / tiled texture.
+ // again, texture frames make this somewhat more complicated than one would think.
+
+ var texture:Texture = this.texture;
+ var frame:Rectangle = texture.frame;
+ var vertexData:VertexData = this.vertexData;
+ var indexData:IndexData = this.indexData;
+ var bounds:Rectangle = getBounds(this, sBounds);
+ var prevNumVertices:int = vertexData.numVertices;
+ var color:uint = prevNumVertices ? vertexData.getColor(0) : 0xffffff;
+ var alpha:Number = prevNumVertices ? vertexData.getAlpha(0) : 1.0;
+ var invScaleX:Number = scaleX > 0 ? 1.0 / scaleX : -1.0 / scaleX;
+ var invScaleY:Number = scaleY > 0 ? 1.0 / scaleY : -1.0 / scaleY;
+ var frameWidth:Number = _tileGrid.width > 0 ? _tileGrid.width : texture.frameWidth;
+ var frameHeight:Number = _tileGrid.height > 0 ? _tileGrid.height : texture.frameHeight;
+
+ frameWidth *= invScaleX;
+ frameHeight *= invScaleY;
+
+ var tileX:Number = frame ? -frame.x * (frameWidth / frame.width) : 0;
+ var tileY:Number = frame ? -frame.y * (frameHeight / frame.height) : 0;
+ var tileWidth:Number = texture.width * (frameWidth / texture.frameWidth);
+ var tileHeight:Number = texture.height * (frameHeight / texture.frameHeight);
+ var modX:Number = (_tileGrid.x * invScaleX) % frameWidth;
+ var modY:Number = (_tileGrid.y * invScaleY) % frameHeight;
+
+ if (modX < 0) modX += frameWidth;
+ if (modY < 0) modY += frameHeight;
+
+ var startX:Number = modX + tileX;
+ var startY:Number = modY + tileY;
+
+ if (startX > (frameWidth - tileWidth)) startX -= frameWidth;
+ if (startY > (frameHeight - tileHeight)) startY -= frameHeight;
+
+ var posLeft:Number, posRight:Number, posTop:Number, posBottom:Number;
+ var texLeft:Number, texRight:Number, texTop:Number, texBottom:Number;
+ var posAttrName:String = "position";
+ var texAttrName:String = "texCoords";
+ var currentX:Number;
+ var currentY:Number = startY;
+ var vertexID:int = 0;
+
+ indexData.numIndices = 0;
+
+ while (currentY < bounds.height)
+ {
+ currentX = startX;
+
+ while (currentX < bounds.width)
+ {
+ indexData.addQuad(vertexID, vertexID + 1, vertexID + 2, vertexID + 3);
+
+ posLeft = currentX < 0 ? 0 : currentX;
+ posTop = currentY < 0 ? 0 : currentY;
+ posRight = currentX + tileWidth > bounds.width ? bounds.width : currentX + tileWidth;
+ posBottom = currentY + tileHeight > bounds.height ? bounds.height : currentY + tileHeight;
+
+ vertexData.setPoint(vertexID, posAttrName, posLeft, posTop);
+ vertexData.setPoint(vertexID + 1, posAttrName, posRight, posTop);
+ vertexData.setPoint(vertexID + 2, posAttrName, posLeft, posBottom);
+ vertexData.setPoint(vertexID + 3, posAttrName, posRight, posBottom);
+
+ texLeft = (posLeft - currentX) / tileWidth;
+ texTop = (posTop - currentY) / tileHeight;
+ texRight = (posRight - currentX) / tileWidth;
+ texBottom = (posBottom - currentY) / tileHeight;
+
+ texture.setTexCoords(vertexData, vertexID, texAttrName, texLeft, texTop);
+ texture.setTexCoords(vertexData, vertexID + 1, texAttrName, texRight, texTop);
+ texture.setTexCoords(vertexData, vertexID + 2, texAttrName, texLeft, texBottom);
+ texture.setTexCoords(vertexData, vertexID + 3, texAttrName, texRight, texBottom);
+
+ currentX += frameWidth;
+ vertexID += 4;
+ }
+
+ currentY += frameHeight;
+ }
+
+ // trim to actual size
+ vertexData.numVertices = vertexID;
+
+ for (var i:int = prevNumVertices; i < vertexID; ++i)
+ {
+ vertexData.setColor(i, "color", color);
+ vertexData.setAlpha(i, "color", alpha);
+ }
+
+ setRequiresRedraw();
+ }
+ }
+}
diff --git a/mobile_version/src/starling/display/Mesh.as b/mobile_version/src/starling/display/Mesh.as
new file mode 100644
index 00000000..82977fba
--- /dev/null
+++ b/mobile_version/src/starling/display/Mesh.as
@@ -0,0 +1,332 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+
+ import starling.core.starling_internal;
+ import starling.geom.Polygon;
+ import starling.rendering.IndexData;
+ import starling.rendering.Painter;
+ import starling.rendering.VertexData;
+ import starling.rendering.VertexDataFormat;
+ import starling.styles.MeshStyle;
+ import starling.textures.Texture;
+ import starling.utils.MatrixUtil;
+ import starling.utils.MeshUtil;
+ import starling.utils.execute;
+
+ use namespace starling_internal;
+
+ /** The base class for all tangible (non-container) display objects, spawned up by a number
+ * of triangles.
+ *
+ *
Since Starling uses Stage3D for rendering, all rendered objects must be constructed
+ * from triangles. A mesh stores the information of its triangles through VertexData and
+ * IndexData structures. The default format stores position, color and texture coordinates
+ * for each vertex.
+ *
+ *
How a mesh is rendered depends on its style. Per default, this is an instance
+ * of the MeshStyle base class; however, subclasses may extend its behavior
+ * to add support for color transformations, normal mapping, etc.
+ *
+ * @see MeshBatch
+ * @see starling.styles.MeshStyle
+ * @see starling.rendering.VertexData
+ * @see starling.rendering.IndexData
+ */
+ public class Mesh extends DisplayObject
+ {
+ /** @private */ internal var _style:MeshStyle;
+ /** @private */ internal var _vertexData:VertexData;
+ /** @private */ internal var _indexData:IndexData;
+ /** @private */ internal var _pixelSnapping:Boolean;
+
+ private static var sDefaultStyle:Class = MeshStyle;
+ private static var sDefaultStyleFactory:Function = null;
+
+ /** Creates a new mesh with the given vertices and indices.
+ * If you don't pass a style, an instance of MeshStyle will be created
+ * for you. Note that the format of the vertex data will be matched to the
+ * given style right away. */
+ public function Mesh(vertexData:VertexData, indexData:IndexData, style:MeshStyle=null)
+ {
+ if (vertexData == null) throw new ArgumentError("VertexData must not be null");
+ if (indexData == null) throw new ArgumentError("IndexData must not be null");
+
+ _vertexData = vertexData;
+ _indexData = indexData;
+
+ setStyle(style, false);
+ }
+
+ /** @inheritDoc */
+ override public function dispose():void
+ {
+ _vertexData.clear();
+ _indexData.clear();
+
+ super.dispose();
+ }
+
+ /** @inheritDoc */
+ override public function hitTest(localPoint:Point):DisplayObject
+ {
+ if (!visible || !touchable || !hitTestMask(localPoint)) return null;
+ else return MeshUtil.containsPoint(_vertexData, _indexData, localPoint) ? this : null;
+ }
+
+ /** @inheritDoc */
+ override public function getBounds(targetSpace:DisplayObject, out:Rectangle=null):Rectangle
+ {
+ return MeshUtil.calculateBounds(_vertexData, this, targetSpace, out);
+ }
+
+ /** @inheritDoc */
+ override public function render(painter:Painter):void
+ {
+ if (_pixelSnapping)
+ MatrixUtil.snapToPixels(painter.state.modelviewMatrix, painter.pixelSize);
+
+ painter.batchMesh(this);
+ }
+
+ /** Sets the style that is used to render the mesh. Styles (which are always subclasses of
+ * MeshStyle) provide a means to completely modify the way a mesh is rendered.
+ * For example, they may add support for color transformations or normal mapping.
+ *
+ *
When assigning a new style, the vertex format will be changed to fit it.
+ * Do not use the same style instance on multiple objects! Instead, make use of
+ * style.clone() to assign an identical style to multiple meshes.
+ *
+ * @param meshStyle the style to assign. If null, the default
+ * style will be created.
+ * @param mergeWithPredecessor if enabled, all attributes of the previous style will be
+ * be copied to the new one, if possible.
+ * @see #defaultStyle
+ * @see #defaultStyleFactory
+ */
+ public function setStyle(meshStyle:MeshStyle=null, mergeWithPredecessor:Boolean=true):void
+ {
+ if (meshStyle == null) meshStyle = createDefaultMeshStyle();
+ else if (meshStyle == _style) return;
+ else if (meshStyle.target) meshStyle.target.setStyle();
+
+ if (_style)
+ {
+ if (mergeWithPredecessor) meshStyle.copyFrom(_style);
+ _style.setTarget(null);
+ }
+
+ _style = meshStyle;
+ _style.setTarget(this, _vertexData, _indexData);
+ }
+
+ private function createDefaultMeshStyle():MeshStyle
+ {
+ var meshStyle:MeshStyle;
+
+ if (sDefaultStyleFactory != null)
+ {
+ if (sDefaultStyleFactory.length == 0) meshStyle = sDefaultStyleFactory();
+ else meshStyle = sDefaultStyleFactory(this);
+ }
+
+ if (meshStyle == null)
+ meshStyle = new sDefaultStyle() as MeshStyle;
+
+ return meshStyle;
+ }
+
+ /** This method is called whenever the mesh's vertex data was changed.
+ * The base implementation simply forwards to setRequiresRedraw. */
+ public function setVertexDataChanged():void
+ {
+ setRequiresRedraw();
+ }
+
+ /** This method is called whenever the mesh's index data was changed.
+ * The base implementation simply forwards to setRequiresRedraw. */
+ public function setIndexDataChanged():void
+ {
+ setRequiresRedraw();
+ }
+
+ // vertex manipulation
+
+ /** The position of the vertex at the specified index, in the mesh's local coordinate
+ * system.
+ *
+ *
Only modify the position of a vertex if you know exactly what you're doing, as
+ * some classes might not work correctly when their vertices are moved. E.g. the
+ * Quad class expects its vertices to spawn up a perfectly rectangular
+ * area; some of its optimized methods won't work correctly if that premise is no longer
+ * fulfilled or the original bounds change.
+ */
+ public function getVertexPosition(vertexID:int, out:Point=null):Point
+ {
+ return _style.getVertexPosition(vertexID, out);
+ }
+
+ public function setVertexPosition(vertexID:int, x:Number, y:Number):void
+ {
+ _style.setVertexPosition(vertexID, x, y);
+ }
+
+ /** Returns the alpha value of the vertex at the specified index. */
+ public function getVertexAlpha(vertexID:int):Number
+ {
+ return _style.getVertexAlpha(vertexID);
+ }
+
+ /** Sets the alpha value of the vertex at the specified index to a certain value. */
+ public function setVertexAlpha(vertexID:int, alpha:Number):void
+ {
+ _style.setVertexAlpha(vertexID, alpha);
+ }
+
+ /** Returns the RGB color of the vertex at the specified index. */
+ public function getVertexColor(vertexID:int):uint
+ {
+ return _style.getVertexColor(vertexID);
+ }
+
+ /** Sets the RGB color of the vertex at the specified index to a certain value. */
+ public function setVertexColor(vertexID:int, color:uint):void
+ {
+ _style.setVertexColor(vertexID, color);
+ }
+
+ /** Returns the texture coordinates of the vertex at the specified index. */
+ public function getTexCoords(vertexID:int, out:Point = null):Point
+ {
+ return _style.getTexCoords(vertexID, out);
+ }
+
+ /** Sets the texture coordinates of the vertex at the specified index to the given values. */
+ public function setTexCoords(vertexID:int, u:Number, v:Number):void
+ {
+ _style.setTexCoords(vertexID, u, v);
+ }
+
+ // properties
+
+ /** The vertex data describing all vertices of the mesh.
+ * Any change requires a call to setRequiresRedraw. */
+ protected function get vertexData():VertexData { return _vertexData; }
+
+ /** The index data describing how the vertices are interconnected.
+ * Any change requires a call to setRequiresRedraw. */
+ protected function get indexData():IndexData { return _indexData; }
+
+ /** The style that is used to render the mesh. Styles (which are always subclasses of
+ * MeshStyle) provide a means to completely modify the way a mesh is rendered.
+ * For example, they may add support for color transformations or normal mapping.
+ *
+ *
The setter will simply forward the assignee to setStyle(value).
+ *
+ * @default MeshStyle
+ */
+ public function get style():MeshStyle { return _style; }
+ public function set style(value:MeshStyle):void
+ {
+ setStyle(value);
+ }
+
+ /** The texture that is mapped to the mesh (or null, if there is none). */
+ public function get texture():Texture { return _style.texture; }
+ public function set texture(value:Texture):void { _style.texture = value; }
+
+ /** Changes the color of all vertices to the same value.
+ * The getter simply returns the color of the first vertex. */
+ public function get color():uint { return _style.color; }
+ public function set color(value:uint):void { _style.color = value; }
+
+ /** The smoothing filter that is used for the texture.
+ * @default bilinear */
+ public function get textureSmoothing():String { return _style.textureSmoothing; }
+ public function set textureSmoothing(value:String):void { _style.textureSmoothing = value; }
+
+ /** Indicates if pixels at the edges will be repeated or clamped. Only works for
+ * power-of-two textures; for a solution that works with all kinds of textures,
+ * see Image.tileGrid. @default false */
+ public function get textureRepeat():Boolean { return _style.textureRepeat; }
+ public function set textureRepeat(value:Boolean):void { _style.textureRepeat = value; }
+
+ /** Controls whether or not the instance snaps to the nearest pixel. This can prevent the
+ * object from looking blurry when it's not exactly aligned with the pixels of the screen.
+ * @default false */
+ public function get pixelSnapping():Boolean { return _pixelSnapping; }
+ public function set pixelSnapping(value:Boolean):void { _pixelSnapping = value; }
+
+ /** The total number of vertices in the mesh. */
+ public function get numVertices():int { return _vertexData.numVertices; }
+
+ /** The total number of indices referencing vertices. */
+ public function get numIndices():int { return _indexData.numIndices; }
+
+ /** The total number of triangles in this mesh.
+ * (In other words: the number of indices divided by three.) */
+ public function get numTriangles():int { return _indexData.numTriangles; }
+
+ /** The format used to store the vertices. */
+ public function get vertexFormat():VertexDataFormat { return _style.vertexFormat; }
+
+ // static properties
+
+ /** The default style used for meshes if no specific style is provided. The default is
+ * starling.rendering.MeshStyle, and any assigned class must be a subclass
+ * of the same. */
+ public static function get defaultStyle():Class { return sDefaultStyle; }
+ public static function set defaultStyle(value:Class):void
+ {
+ sDefaultStyle = value;
+ }
+
+ /** A factory method that is used to create the 'MeshStyle' for a mesh if no specific
+ * style is provided. That's useful if you are creating a hierarchy of objects, all
+ * of which need to have a certain style. Different to the defaultStyle
+ * property, this method allows plugging in custom logic and passing arguments to the
+ * constructor. Return null to fall back to the default behavior (i.e.
+ * to instantiate defaultStyle). The mesh-parameter is optional
+ * and may be omitted.
+ *
+ *
+ * Mesh.defaultStyleFactory = function(mesh:Mesh):MeshStyle
+ * {
+ * return new ColorizeMeshStyle(Math.random() * 0xffffff);
+ * }
+ */
+ public static function get defaultStyleFactory():Function { return sDefaultStyleFactory; }
+ public static function set defaultStyleFactory(value:Function):void
+ {
+ sDefaultStyleFactory = value;
+ }
+
+ // static methods
+
+ /** Creates a mesh from the specified polygon.
+ * Vertex positions and indices will be set up according to the polygon;
+ * any other vertex attributes (e.g. texture coordinates) need to be set up manually.
+ */
+ public static function fromPolygon(polygon:Polygon, style:MeshStyle=null):Mesh
+ {
+ var vertexData:VertexData = new VertexData(null, polygon.numVertices);
+ var indexData:IndexData = new IndexData(polygon.numTriangles);
+
+ polygon.copyToVertexData(vertexData);
+ polygon.triangulate(indexData);
+
+ return new Mesh(vertexData, indexData, style);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/display/MeshBatch.as b/mobile_version/src/starling/display/MeshBatch.as
new file mode 100644
index 00000000..50ae1c0e
--- /dev/null
+++ b/mobile_version/src/starling/display/MeshBatch.as
@@ -0,0 +1,300 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Matrix;
+
+ import starling.rendering.IndexData;
+ import starling.rendering.MeshEffect;
+ import starling.rendering.Painter;
+ import starling.rendering.VertexData;
+ import starling.styles.MeshStyle;
+ import starling.utils.MatrixUtil;
+ import starling.utils.MeshSubset;
+
+ /** Combines a number of meshes to one display object and renders them efficiently.
+ *
+ *
The most basic tangible (non-container) display object in Starling is the Mesh.
+ * However, a mesh typically does not render itself; it just holds the data describing its
+ * geometry. Rendering is orchestrated by the "MeshBatch" class. As its name suggests, it
+ * acts as a batch for an arbitrary number of Mesh instances; add meshes to a batch and they
+ * are all rendered together, in one draw call.
+ *
+ *
You can only batch meshes that share similar properties, e.g. they need to have the
+ * same texture and the same blend mode. The first object you add to a batch will decide
+ * this state; call canAddMesh to find out if a new mesh shares that state.
+ * To reset the current state, you can call clear; this will also remove all
+ * geometry that has been added thus far.
+ *
+ *
Starling will use MeshBatch instances (or compatible objects) for all rendering.
+ * However, you can also instantiate MeshBatch instances yourself and add them to the display
+ * tree. That makes sense for an object containing a large number of meshes; that way, that
+ * object can be created once and then rendered very efficiently, without having to copy its
+ * vertices and indices between buffers and GPU memory.
+ *
+ * @see Mesh
+ * @see Sprite
+ */
+ public class MeshBatch extends Mesh
+ {
+ /** The maximum number of vertices that fit into one MeshBatch. */
+ public static const MAX_NUM_VERTICES:int = 65535;
+
+ private var _effect:MeshEffect;
+ private var _batchable:Boolean;
+ private var _vertexSyncRequired:Boolean;
+ private var _indexSyncRequired:Boolean;
+
+ // helper object
+ private static var sFullMeshSubset:MeshSubset = new MeshSubset();
+
+ /** Creates a new, empty MeshBatch instance. */
+ public function MeshBatch()
+ {
+ var vertexData:VertexData = new VertexData();
+ var indexData:IndexData = new IndexData();
+
+ super(vertexData, indexData);
+ }
+
+ /** @inheritDoc */
+ override public function dispose():void
+ {
+ if (_effect) _effect.dispose();
+ super.dispose();
+ }
+
+ /** This method must be called whenever the mesh's vertex data was changed. Makes
+ * sure that the vertex buffer is synchronized before rendering, and forces a redraw. */
+ override public function setVertexDataChanged():void
+ {
+ _vertexSyncRequired = true;
+ super.setVertexDataChanged();
+ }
+
+ /** This method must be called whenever the mesh's index data was changed. Makes
+ * sure that the index buffer is synchronized before rendering, and forces a redraw. */
+ override public function setIndexDataChanged():void
+ {
+ _indexSyncRequired = true;
+ super.setIndexDataChanged();
+ }
+
+ private function setVertexAndIndexDataChanged():void
+ {
+ _vertexSyncRequired = _indexSyncRequired = true;
+ }
+
+ private function syncVertexBuffer():void
+ {
+ _effect.uploadVertexData(_vertexData);
+ _vertexSyncRequired = false;
+ }
+
+ private function syncIndexBuffer():void
+ {
+ _effect.uploadIndexData(_indexData);
+ _indexSyncRequired = false;
+ }
+
+ /** Removes all geometry. */
+ public function clear():void
+ {
+ if (_parent) setRequiresRedraw();
+
+ _vertexData.numVertices = 0;
+ _indexData.numIndices = 0;
+ _vertexSyncRequired = true;
+ _indexSyncRequired = true;
+ }
+
+ /** Adds a mesh to the batch by appending its vertices and indices.
+ *
+ * @param mesh the mesh to add to the batch.
+ * @param matrix transform all vertex positions with a certain matrix. If this
+ * parameter is omitted, mesh.transformationMatrix
+ * will be used instead (except if the last parameter is enabled).
+ * @param alpha will be multiplied with each vertex' alpha value.
+ * @param subset the subset of the mesh you want to add, or null for
+ * the complete mesh.
+ * @param ignoreTransformations when enabled, the mesh's vertices will be added
+ * without transforming them in any way (no matter the value of the
+ * matrix parameter).
+ */
+ public function addMesh(mesh:Mesh, matrix:Matrix=null, alpha:Number=1.0,
+ subset:MeshSubset=null, ignoreTransformations:Boolean=false):void
+ {
+ if (ignoreTransformations) matrix = null;
+ else if (matrix == null) matrix = mesh.transformationMatrix;
+ if (subset == null) subset = sFullMeshSubset;
+
+ var targetVertexID:int = _vertexData.numVertices;
+ var targetIndexID:int = _indexData.numIndices;
+ var meshStyle:MeshStyle = mesh._style;
+
+ if (targetVertexID == 0)
+ setupFor(mesh);
+
+ meshStyle.batchVertexData(_style, targetVertexID, matrix, subset.vertexID, subset.numVertices);
+ meshStyle.batchIndexData(_style, targetIndexID, targetVertexID - subset.vertexID,
+ subset.indexID, subset.numIndices);
+
+ if (alpha != 1.0) _vertexData.scaleAlphas("color", alpha, targetVertexID, subset.numVertices);
+ if (_parent) setRequiresRedraw();
+
+ _indexSyncRequired = _vertexSyncRequired = true;
+ }
+
+ /** Adds a mesh to the batch by copying its vertices and indices to the given positions.
+ * Beware that you need to check for yourself if those positions make sense; for example,
+ * you need to make sure that they are aligned within the 3-indices groups making up
+ * the mesh's triangles.
+ *
+ *
It's easiest to only add objects with an identical setup, e.g. only quads.
+ * For the latter, indices are aligned in groups of 6 (one quad requires six indices),
+ * and the vertices in groups of 4 (one vertex for every corner).
+ */
+ public function addMeshAt(mesh:Mesh, indexID:int, vertexID:int):void
+ {
+ var numIndices:int = mesh.numIndices;
+ var numVertices:int = mesh.numVertices;
+ var matrix:Matrix = mesh.transformationMatrix;
+ var meshStyle:MeshStyle = mesh._style;
+
+ if (_vertexData.numVertices == 0)
+ setupFor(mesh);
+
+ meshStyle.batchVertexData(_style, vertexID, matrix, 0, numVertices);
+ meshStyle.batchIndexData(_style, indexID, vertexID, 0, numIndices);
+
+ if (alpha != 1.0) _vertexData.scaleAlphas("color", alpha, vertexID, numVertices);
+ if (_parent) setRequiresRedraw();
+
+ _indexSyncRequired = _vertexSyncRequired = true;
+ }
+
+ private function setupFor(mesh:Mesh):void
+ {
+ var meshStyle:MeshStyle = mesh._style;
+ var meshStyleType:Class = meshStyle.type;
+
+ if (_style.type != meshStyleType)
+ setStyle(new meshStyleType() as MeshStyle, false);
+
+ _style.copyFrom(meshStyle);
+ }
+
+ /** Indicates if the given mesh instance fits to the current state of the batch.
+ * Will always return true for the first added mesh; later calls
+ * will check if the style matches and if the maximum number of vertices is not
+ * exceeded.
+ *
+ * @param mesh the mesh to add to the batch.
+ * @param numVertices if -1, mesh.numVertices will be used
+ */
+ public function canAddMesh(mesh:Mesh, numVertices:int=-1):Boolean
+ {
+ var currentNumVertices:int = _vertexData.numVertices;
+
+ if (currentNumVertices == 0) return true;
+ if (numVertices < 0) numVertices = mesh.numVertices;
+ if (numVertices == 0) return true;
+ if (numVertices + currentNumVertices > MAX_NUM_VERTICES) return false;
+
+ return _style.canBatchWith(mesh._style);
+ }
+
+ /** If the batchable property is enabled, this method will add the batch
+ * to the painter's current batch. Otherwise, this will actually do the drawing. */
+ override public function render(painter:Painter):void
+ {
+ if (_vertexData.numVertices == 0) return;
+ if (_pixelSnapping) MatrixUtil.snapToPixels(
+ painter.state.modelviewMatrix, painter.pixelSize);
+
+ if (_batchable)
+ {
+ painter.batchMesh(this);
+ }
+ else
+ {
+ painter.finishMeshBatch();
+ painter.drawCount += 1;
+ painter.prepareToDraw();
+ painter.excludeFromCache(this);
+
+ if (_vertexSyncRequired) syncVertexBuffer();
+ if (_indexSyncRequired) syncIndexBuffer();
+
+ _style.updateEffect(_effect, painter.state);
+ _effect.render(0, _indexData.numTriangles);
+ }
+ }
+
+ /** @inheritDoc */
+ override public function setStyle(meshStyle:MeshStyle=null,
+ mergeWithPredecessor:Boolean=true):void
+ {
+ super.setStyle(meshStyle, mergeWithPredecessor);
+
+ if (_effect)
+ _effect.dispose();
+
+ _effect = style.createEffect();
+ _effect.onRestore = setVertexAndIndexDataChanged;
+ }
+
+ /** The total number of vertices in the mesh. If you change this to a smaller value,
+ * the surplus will be deleted. Make sure that no indices reference those deleted
+ * vertices! */
+ public function set numVertices(value:int):void
+ {
+ if (_vertexData.numVertices != value)
+ {
+ _vertexData.numVertices = value;
+ _vertexSyncRequired = true;
+ setRequiresRedraw();
+ }
+ }
+
+ /** The total number of indices in the mesh. If you change this to a smaller value,
+ * the surplus will be deleted. Always make sure that the number of indices
+ * is a multiple of three! */
+ public function set numIndices(value:int):void
+ {
+ if (_indexData.numIndices != value)
+ {
+ _indexData.numIndices = value;
+ _indexSyncRequired = true;
+ setRequiresRedraw();
+ }
+ }
+
+ /** Indicates if this object will be added to the painter's batch on rendering,
+ * or if it will draw itself right away.
+ *
+ *
Only batchable meshes can profit from the render cache; but batching large meshes
+ * may take up a lot of CPU time. Activate this property only if the batch contains just
+ * a handful of vertices (say, 20 quads).
+ *
+ * @default false
+ */
+ public function get batchable():Boolean { return _batchable; }
+ public function set batchable(value:Boolean):void
+ {
+ if (_batchable != value)
+ {
+ _batchable = value;
+ setRequiresRedraw();
+ }
+ }
+ }
+}
diff --git a/mobile_version/src/starling/display/MovieClip.as b/mobile_version/src/starling/display/MovieClip.as
new file mode 100644
index 00000000..320a4a2a
--- /dev/null
+++ b/mobile_version/src/starling/display/MovieClip.as
@@ -0,0 +1,479 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.errors.IllegalOperationError;
+ import flash.media.Sound;
+ import flash.media.SoundTransform;
+
+ import starling.animation.IAnimatable;
+ import starling.events.Event;
+ import starling.textures.Texture;
+
+ /** Dispatched whenever the movie has displayed its last frame. */
+ [Event(name="complete", type="starling.events.Event")]
+
+ /** A MovieClip is a simple way to display an animation depicted by a list of textures.
+ *
+ *
Pass the frames of the movie in a vector of textures to the constructor. The movie clip
+ * will have the width and height of the first frame. If you group your frames with the help
+ * of a texture atlas (which is recommended), use the getTextures-method of the
+ * atlas to receive the textures in the correct (alphabetic) order.
+ *
+ *
You can specify the desired framerate via the constructor. You can, however, manually
+ * give each frame a custom duration. You can also play a sound whenever a certain frame
+ * appears, or execute a callback (a "frame action").
+ *
+ *
The methods play and pause control playback of the movie. You
+ * will receive an event of type Event.COMPLETE when the movie finished
+ * playback. If the movie is looping, the event is dispatched once per loop.
+ *
+ *
As any animated object, a movie clip has to be added to a juggler (or have its
+ * advanceTime method called regularly) to run. The movie will dispatch
+ * an event of type "Event.COMPLETE" whenever it has displayed its last frame.
+ *
+ * @see starling.textures.TextureAtlas
+ */
+ public class MovieClip extends Image implements IAnimatable
+ {
+ private var _frames:Vector.;
+ private var _defaultFrameDuration:Number;
+ private var _currentTime:Number;
+ private var _currentFrameID:int;
+ private var _loop:Boolean;
+ private var _playing:Boolean;
+ private var _muted:Boolean;
+ private var _wasStopped:Boolean;
+ private var _soundTransform:SoundTransform;
+
+ /** Creates a movie clip from the provided textures and with the specified default framerate.
+ * The movie will have the size of the first frame. */
+ public function MovieClip(textures:Vector., fps:Number=12)
+ {
+ if (textures.length > 0)
+ {
+ super(textures[0]);
+ init(textures, fps);
+ }
+ else
+ {
+ throw new ArgumentError("Empty texture array");
+ }
+ }
+
+ private function init(textures:Vector., fps:Number):void
+ {
+ if (fps <= 0) throw new ArgumentError("Invalid fps: " + fps);
+ var numFrames:int = textures.length;
+
+ _defaultFrameDuration = 1.0 / fps;
+ _loop = true;
+ _playing = true;
+ _currentTime = 0.0;
+ _currentFrameID = 0;
+ _wasStopped = true;
+ _frames = new [];
+
+ for (var i:int=0; i numFrames) throw new ArgumentError("Invalid frame id");
+ if (duration < 0) duration = _defaultFrameDuration;
+
+ var frame:MovieClipFrame = new MovieClipFrame(texture, duration);
+ frame.sound = sound;
+ _frames.insertAt(frameID, frame);
+
+ if (frameID == numFrames)
+ {
+ var prevStartTime:Number = frameID > 0 ? _frames[frameID - 1].startTime : 0.0;
+ var prevDuration:Number = frameID > 0 ? _frames[frameID - 1].duration : 0.0;
+ frame.startTime = prevStartTime + prevDuration;
+ }
+ else
+ updateStartTimes();
+ }
+
+ /** Removes the frame at a certain ID. The successors will move down. */
+ public function removeFrameAt(frameID:int):void
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ if (numFrames == 1) throw new IllegalOperationError("Movie clip must not be empty");
+
+ _frames.removeAt(frameID);
+
+ if (frameID != numFrames)
+ updateStartTimes();
+ }
+
+ /** Returns the texture of a certain frame. */
+ public function getFrameTexture(frameID:int):Texture
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ return _frames[frameID].texture;
+ }
+
+ /** Sets the texture of a certain frame. */
+ public function setFrameTexture(frameID:int, texture:Texture):void
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ _frames[frameID].texture = texture;
+ }
+
+ /** Returns the sound of a certain frame. */
+ public function getFrameSound(frameID:int):Sound
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ return _frames[frameID].sound;
+ }
+
+ /** Sets the sound of a certain frame. The sound will be played whenever the frame
+ * is displayed. */
+ public function setFrameSound(frameID:int, sound:Sound):void
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ _frames[frameID].sound = sound;
+ }
+
+ /** Returns the method that is executed at a certain frame. */
+ public function getFrameAction(frameID:int):Function
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ return _frames[frameID].action;
+ }
+
+ /** Sets an action that will be executed whenever a certain frame is reached. */
+ public function setFrameAction(frameID:int, action:Function):void
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ _frames[frameID].action = action;
+ }
+
+ /** Returns the duration of a certain frame (in seconds). */
+ public function getFrameDuration(frameID:int):Number
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ return _frames[frameID].duration;
+ }
+
+ /** Sets the duration of a certain frame (in seconds). */
+ public function setFrameDuration(frameID:int, duration:Number):void
+ {
+ if (frameID < 0 || frameID >= numFrames) throw new ArgumentError("Invalid frame id");
+ _frames[frameID].duration = duration;
+ updateStartTimes();
+ }
+
+ /** Reverses the order of all frames, making the clip run from end to start.
+ * Makes sure that the currently visible frame stays the same. */
+ public function reverseFrames():void
+ {
+ _frames.reverse();
+ _currentTime = totalTime - _currentTime;
+ _currentFrameID = numFrames - _currentFrameID - 1;
+ updateStartTimes();
+ }
+
+ // playback methods
+
+ /** Starts playback. Beware that the clip has to be added to a juggler, too! */
+ public function play():void
+ {
+ _playing = true;
+ }
+
+ /** Pauses playback. */
+ public function pause():void
+ {
+ _playing = false;
+ }
+
+ /** Stops playback, resetting "currentFrame" to zero. */
+ public function stop():void
+ {
+ _playing = false;
+ _wasStopped = true;
+ currentFrame = 0;
+ }
+
+ // helpers
+
+ private function updateStartTimes():void
+ {
+ var numFrames:int = this.numFrames;
+ var prevFrame:MovieClipFrame = _frames[0];
+ prevFrame.startTime = 0;
+
+ for (var i:int=1; i= restTimeInFrame)
+ {
+ changedFrame = false;
+ passedTime -= restTimeInFrame;
+ _currentTime = frame.startTime + frame.duration;
+
+ if (_currentFrameID == finalFrameID)
+ {
+ if (hasEventListener(Event.COMPLETE))
+ {
+ dispatchCompleteEvent = true;
+ }
+ else if (_loop)
+ {
+ _currentTime = 0;
+ _currentFrameID = 0;
+ changedFrame = true;
+ }
+ else return;
+ }
+ else
+ {
+ _currentFrameID += 1;
+ changedFrame = true;
+ }
+
+ frame = _frames[_currentFrameID];
+ frameAction = frame.action;
+
+ if (changedFrame)
+ frame.playSound(_soundTransform);
+
+ if (dispatchCompleteEvent)
+ {
+ texture = frame.texture;
+ dispatchEventWith(Event.COMPLETE);
+ advanceTime(passedTime);
+ return;
+ }
+ else if (frameAction != null)
+ {
+ texture = frame.texture;
+ frame.executeAction(this, _currentFrameID);
+ advanceTime(passedTime);
+ return;
+ }
+
+ restTimeInFrame = frame.duration;
+
+ // prevent a mean floating point problem (issue #851)
+ if (passedTime + 0.0001 > restTimeInFrame && passedTime - 0.0001 < restTimeInFrame)
+ passedTime = restTimeInFrame;
+ }
+
+ if (previousFrameID != _currentFrameID)
+ texture = _frames[_currentFrameID].texture;
+
+ _currentTime += passedTime;
+ }
+
+ // properties
+
+ /** The total number of frames. */
+ public function get numFrames():int { return _frames.length; }
+
+ /** The total duration of the clip in seconds. */
+ public function get totalTime():Number
+ {
+ var lastFrame:MovieClipFrame = _frames[_frames.length-1];
+ return lastFrame.startTime + lastFrame.duration;
+ }
+
+ /** The time that has passed since the clip was started (each loop starts at zero). */
+ public function get currentTime():Number { return _currentTime; }
+ public function set currentTime(value:Number):void
+ {
+ if (value < 0 || value > totalTime) throw new ArgumentError("Invalid time: " + value);
+
+ var lastFrameID:int = _frames.length - 1;
+ _currentTime = value;
+ _currentFrameID = 0;
+
+ while (_currentFrameID < lastFrameID && _frames[_currentFrameID + 1].startTime <= value)
+ ++_currentFrameID;
+
+ var frame:MovieClipFrame = _frames[_currentFrameID];
+ texture = frame.texture;
+ }
+
+ /** Indicates if the clip should loop. @default true */
+ public function get loop():Boolean { return _loop; }
+ public function set loop(value:Boolean):void { _loop = value; }
+
+ /** If enabled, no new sounds will be started during playback. Sounds that are already
+ * playing are not affected. */
+ public function get muted():Boolean { return _muted; }
+ public function set muted(value:Boolean):void { _muted = value; }
+
+ /** The SoundTransform object used for playback of all frame sounds. @default null */
+ public function get soundTransform():SoundTransform { return _soundTransform; }
+ public function set soundTransform(value:SoundTransform):void { _soundTransform = value; }
+
+ /** The index of the frame that is currently displayed. */
+ public function get currentFrame():int { return _currentFrameID; }
+ public function set currentFrame(value:int):void
+ {
+ if (value < 0 || value >= numFrames) throw new ArgumentError("Invalid frame id");
+ currentTime = _frames[value].startTime;
+ }
+
+ /** The default number of frames per second. Individual frames can have different
+ * durations. If you change the fps, the durations of all frames will be scaled
+ * relatively to the previous value. */
+ public function get fps():Number { return 1.0 / _defaultFrameDuration; }
+ public function set fps(value:Number):void
+ {
+ if (value <= 0) throw new ArgumentError("Invalid fps: " + value);
+
+ var newFrameDuration:Number = 1.0 / value;
+ var acceleration:Number = newFrameDuration / _defaultFrameDuration;
+ _currentTime *= acceleration;
+ _defaultFrameDuration = newFrameDuration;
+
+ for (var i:int=0; ifalse when the end
+ * is reached. */
+ public function get isPlaying():Boolean
+ {
+ if (_playing)
+ return _loop || _currentTime < totalTime;
+ else
+ return false;
+ }
+
+ /** Indicates if a (non-looping) movie has come to its end. */
+ public function get isComplete():Boolean
+ {
+ return !_loop && _currentTime >= totalTime;
+ }
+ }
+}
+
+import flash.media.Sound;
+import flash.media.SoundTransform;
+
+import starling.display.MovieClip;
+import starling.textures.Texture;
+
+class MovieClipFrame
+{
+ public function MovieClipFrame(texture:Texture, duration:Number=0.1, startTime:Number=0)
+ {
+ this.texture = texture;
+ this.duration = duration;
+ this.startTime = startTime;
+ }
+
+ public var texture:Texture;
+ public var sound:Sound;
+ public var duration:Number;
+ public var startTime:Number;
+ public var action:Function;
+
+ public function playSound(transform:SoundTransform):void
+ {
+ if (sound) sound.play(0, 0, transform);
+ }
+
+ public function executeAction(movie:MovieClip, frameID:int):void
+ {
+ if (action != null)
+ {
+ var numArgs:int = action.length;
+
+ if (numArgs == 0) action();
+ else if (numArgs == 1) action(movie);
+ else if (numArgs == 2) action(movie, frameID);
+ else throw new Error("Frame actions support zero, one or two parameters: " +
+ "movie:MovieClip, frameID:int");
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/Quad.as b/mobile_version/src/starling/display/Quad.as
new file mode 100644
index 00000000..5c0f1e00
--- /dev/null
+++ b/mobile_version/src/starling/display/Quad.as
@@ -0,0 +1,209 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Matrix;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+ import flash.geom.Vector3D;
+
+ import starling.rendering.IndexData;
+ import starling.rendering.VertexData;
+ import starling.styles.MeshStyle;
+ import starling.textures.Texture;
+ import starling.utils.RectangleUtil;
+
+ /** A Quad represents a colored and/or textured rectangle.
+ *
+ *
Quads may have a color and a texture. When assigning a texture, the colors of the
+ * vertices will "tint" the texture, i.e. the vertex color will be multiplied with the color
+ * of the texture at the same position. That's why the default color of a quad is pure white:
+ * tinting with white does not change the texture color (that's a multiplication with one).
+ *
+ *
A quad is, by definition, always rectangular. The basic quad class will always contain
+ * exactly four vertices, arranged like this:
+ *
+ *
+ * 0 - 1
+ * | / |
+ * 2 - 3
+ *
+ *
+ *
You can set the color of each vertex individually; and since the colors will smoothly
+ * fade into each other over the area of the quad, you can use this to create simple linear
+ * color gradients (e.g. by assigning one color to vertices 0 and 1 and another to vertices
+ * 2 and 3).
+ *
+ *
However, note that the number of vertices may be different in subclasses.
+ * Check the property numVertices if you are unsure.
+ *
+ * @see starling.textures.Texture
+ * @see Image
+ */
+ public class Quad extends Mesh
+ {
+ private var _bounds:Rectangle;
+
+ // helper objects
+ private static var sPoint3D:Vector3D = new Vector3D();
+ private static var sMatrix:Matrix = new Matrix();
+ private static var sMatrix3D:Matrix3D = new Matrix3D();
+
+ /** Creates a quad with a certain size and color. */
+ public function Quad(width:Number, height:Number, color:uint=0xffffff)
+ {
+ _bounds = new Rectangle(0, 0, width, height);
+
+ var vertexData:VertexData = new VertexData(MeshStyle.VERTEX_FORMAT, 4);
+ var indexData:IndexData = new IndexData(6);
+
+ super(vertexData, indexData);
+
+ if (width == 0.0 || height == 0.0)
+ throw new ArgumentError("Invalid size: width and height must not be zero");
+
+ setupVertices();
+ this.color = color;
+ }
+
+ /** Sets up vertex- and index-data according to the current settings. */
+ protected function setupVertices():void
+ {
+ var posAttr:String = "position";
+ var texAttr:String = "texCoords";
+ var texture:Texture = style.texture;
+ var vertexData:VertexData = this.vertexData;
+ var indexData:IndexData = this.indexData;
+
+ indexData.numIndices = 0;
+ indexData.addQuad(0, 1, 2, 3);
+
+ if (vertexData.numVertices != 4)
+ {
+ vertexData.numVertices = 4;
+ vertexData.trim();
+ }
+
+ if (texture)
+ {
+ texture.setupVertexPositions(vertexData, 0, "position", _bounds);
+ texture.setupTextureCoordinates(vertexData, 0, texAttr);
+ }
+ else
+ {
+ vertexData.setPoint(0, posAttr, _bounds.left, _bounds.top);
+ vertexData.setPoint(1, posAttr, _bounds.right, _bounds.top);
+ vertexData.setPoint(2, posAttr, _bounds.left, _bounds.bottom);
+ vertexData.setPoint(3, posAttr, _bounds.right, _bounds.bottom);
+
+ vertexData.setPoint(0, texAttr, 0.0, 0.0);
+ vertexData.setPoint(1, texAttr, 1.0, 0.0);
+ vertexData.setPoint(2, texAttr, 0.0, 1.0);
+ vertexData.setPoint(3, texAttr, 1.0, 1.0);
+ }
+
+ setRequiresRedraw();
+ }
+
+ /** @inheritDoc */
+ public override function getBounds(targetSpace:DisplayObject, out:Rectangle=null):Rectangle
+ {
+ if (out == null) out = new Rectangle();
+
+ if (targetSpace == this) // optimization
+ {
+ out.copyFrom(_bounds);
+ }
+ else if (targetSpace == parent && !isRotated) // optimization
+ {
+ var scaleX:Number = this.scaleX;
+ var scaleY:Number = this.scaleY;
+
+ out.setTo( x - pivotX * scaleX, y - pivotY * scaleY,
+ _bounds.width * scaleX, _bounds.height * scaleY);
+
+ if (scaleX < 0) { out.width *= -1; out.x -= out.width; }
+ if (scaleY < 0) { out.height *= -1; out.y -= out.height; }
+ }
+ else if (is3D && stage)
+ {
+ stage.getCameraPosition(targetSpace, sPoint3D);
+ getTransformationMatrix3D(targetSpace, sMatrix3D);
+ RectangleUtil.getBoundsProjected(_bounds, sMatrix3D, sPoint3D, out);
+ }
+ else
+ {
+ getTransformationMatrix(targetSpace, sMatrix);
+ RectangleUtil.getBounds(_bounds, sMatrix, out);
+ }
+
+ return out;
+ }
+
+ /** @inheritDoc */
+ override public function hitTest(localPoint:Point):DisplayObject
+ {
+ if (!visible || !touchable || !hitTestMask(localPoint)) return null;
+ else if (_bounds.containsPoint(localPoint)) return this;
+ else return null;
+ }
+
+ /** Readjusts the dimensions of the quad. Use this method without any arguments to
+ * synchronize quad and texture size after assigning a texture with a different size.
+ * You can also force a certain width and height by passing positive, non-zero
+ * values for width and height. */
+ public function readjustSize(width:Number=-1, height:Number=-1):void
+ {
+ if (width <= 0) width = texture ? texture.frameWidth : _bounds.width;
+ if (height <= 0) height = texture ? texture.frameHeight : _bounds.height;
+
+ if (width != _bounds.width || height != _bounds.height)
+ {
+ _bounds.setTo(0, 0, width, height);
+ setupVertices();
+ }
+ }
+
+ /** Creates a quad from the given texture.
+ * The quad will have the same size as the texture. */
+ public static function fromTexture(texture:Texture):Quad
+ {
+ var quad:Quad = new Quad(100, 100);
+ quad.texture = texture;
+ quad.readjustSize();
+ return quad;
+ }
+
+ /** The texture that is mapped to the quad (or null, if there is none).
+ * Per default, it is mapped to the complete quad, i.e. to the complete area between the
+ * top left and bottom right vertices. This can be changed with the
+ * setTexCoords-method.
+ *
+ *
Note that the size of the quad will not change when you assign a texture, which
+ * means that the texture might be distorted at first. Call readjustSize to
+ * synchronize quad and texture size.
+ *
+ *
You could also set the texture via the style.texture property.
+ * That way, however, the texture frame won't be taken into account. Since only rectangular
+ * objects can make use of a texture frame, only a property on the Quad class can do that.
+ *
+ */
+ override public function set texture(value:Texture):void
+ {
+ if (value != texture)
+ {
+ super.texture = value;
+ setupVertices();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/Sprite.as b/mobile_version/src/starling/display/Sprite.as
new file mode 100644
index 00000000..2cb45b84
--- /dev/null
+++ b/mobile_version/src/starling/display/Sprite.as
@@ -0,0 +1,27 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ /** A Sprite is the most lightweight, non-abstract container class.
+ * Use it as a simple means of grouping objects together in one coordinate system.
+ *
+ * @see DisplayObject
+ * @see DisplayObjectContainer
+ */
+ public class Sprite extends DisplayObjectContainer
+ {
+ /** Creates an empty sprite. */
+ public function Sprite()
+ {
+ super();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/display/Sprite3D.as b/mobile_version/src/starling/display/Sprite3D.as
new file mode 100644
index 00000000..d8951b03
--- /dev/null
+++ b/mobile_version/src/starling/display/Sprite3D.as
@@ -0,0 +1,372 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.display
+{
+ import flash.geom.Matrix;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Vector3D;
+
+ import starling.events.Event;
+ import starling.rendering.Painter;
+ import starling.utils.MathUtil;
+ import starling.utils.MatrixUtil;
+ import starling.utils.rad2deg;
+
+ /** A container that allows you to position objects in three-dimensional space.
+ *
+ *
Starling is, at its heart, a 2D engine. However, sometimes, simple 3D effects are
+ * useful for special effects, e.g. for screen transitions or to turn playing cards
+ * realistically. This class makes it possible to create such 3D effects.
+ *
+ *
Positioning objects in 3D
+ *
+ *
Just like a normal sprite, you can add and remove children to this container, which
+ * allows you to group several display objects together. In addition to that, Sprite3D
+ * adds some interesting properties:
+ *
+ *
+ *
z - Moves the sprite closer to / further away from the camera.
+ *
rotationX — Rotates the sprite around the x-axis.
+ *
rotationY — Rotates the sprite around the y-axis.
+ *
scaleZ - Scales the sprite along the z-axis.
+ *
pivotZ - Moves the pivot point along the z-axis.
+ *
+ *
+ *
With the help of these properties, you can move a sprite and all its children in the
+ * 3D space. By nesting several Sprite3D containers, it's even possible to construct simple
+ * volumetric objects (like a cube).
+ *
+ *
Note that Starling does not make any z-tests: visibility is solely established by the
+ * order of the children, just as with 2D objects.
+ *
+ *
Setting up the camera
+ *
+ *
The camera settings are found directly on the stage. Modify the 'focalLength' or
+ * 'fieldOfView' properties to change the distance between stage and camera; use the
+ * 'projectionOffset' to move it to a different position.
+ *
+ *
Limitations
+ *
+ *
On rendering, each Sprite3D requires its own draw call — except if the object does not
+ * contain any 3D transformations ('z', 'rotationX/Y' and 'pivotZ' are zero). Furthermore,
+ * it interrupts the render cache, i.e. the cache cannot contain objects within different
+ * 3D coordinate systems. Flat contents within the Sprite3D will be cached, though.
+ *
+ */
+ public class Sprite3D extends DisplayObjectContainer
+ {
+ private static const E:Number = 0.00001;
+
+ private var _rotationX:Number;
+ private var _rotationY:Number;
+ private var _scaleZ:Number;
+ private var _pivotZ:Number;
+ private var _z:Number;
+
+ private var _transformationMatrix:Matrix;
+ private var _transformationMatrix3D:Matrix3D;
+ private var _transformationChanged:Boolean;
+ private var _is2D:Boolean;
+
+ /** Helper objects. */
+ private static var sHelperPoint:Vector3D = new Vector3D();
+ private static var sHelperPointAlt:Vector3D = new Vector3D();
+ private static var sHelperMatrix:Matrix3D = new Matrix3D();
+
+ /** Creates an empty Sprite3D. */
+ public function Sprite3D()
+ {
+ _scaleZ = 1.0;
+ _rotationX = _rotationY = _pivotZ = _z = 0.0;
+ _transformationMatrix = new Matrix();
+ _transformationMatrix3D = new Matrix3D();
+ _is2D = true; // meaning: this 3D object contains only 2D content
+ setIs3D(true); // meaning: this display object supports 3D transformations
+
+ addEventListener(Event.ADDED, onAddedChild);
+ addEventListener(Event.REMOVED, onRemovedChild);
+ }
+
+ /** @inheritDoc */
+ override public function render(painter:Painter):void
+ {
+ if (_is2D) super.render(painter);
+ else
+ {
+ painter.finishMeshBatch();
+ painter.pushState();
+ painter.state.transformModelviewMatrix3D(transformationMatrix3D);
+
+ super.render(painter);
+
+ painter.finishMeshBatch();
+ painter.excludeFromCache(this);
+ painter.popState();
+ }
+ }
+
+ /** @inheritDoc */
+ override public function hitTest(localPoint:Point):DisplayObject
+ {
+ if (_is2D) return super.hitTest(localPoint);
+ else
+ {
+ if (!visible || !touchable) return null;
+
+ // We calculate the interception point between the 3D plane that is spawned up
+ // by this sprite3D and the straight line between the camera and the hit point.
+
+ sHelperMatrix.copyFrom(transformationMatrix3D);
+ sHelperMatrix.invert();
+
+ stage.getCameraPosition(this, sHelperPoint);
+ MatrixUtil.transformCoords3D(sHelperMatrix, localPoint.x, localPoint.y, 0, sHelperPointAlt);
+ MathUtil.intersectLineWithXYPlane(sHelperPoint, sHelperPointAlt, localPoint);
+
+ return super.hitTest(localPoint);
+ }
+ }
+
+ /** @private */
+ override public function setRequiresRedraw():void
+ {
+ _is2D = _z > -E && _z < E &&
+ _rotationX > -E && _rotationX < E &&
+ _rotationY > -E && _rotationY < E &&
+ _pivotZ > -E && _pivotZ < E;
+
+ super.setRequiresRedraw();
+ }
+
+ // helpers
+
+ private function onAddedChild(event:Event):void
+ {
+ recursivelySetIs3D(event.target as DisplayObject, true);
+ }
+
+ private function onRemovedChild(event:Event):void
+ {
+ recursivelySetIs3D(event.target as DisplayObject, false);
+ }
+
+ private function recursivelySetIs3D(object:DisplayObject, value:Boolean):void
+ {
+ if (object is Sprite3D)
+ return;
+
+ if (object is DisplayObjectContainer)
+ {
+ var container:DisplayObjectContainer = object as DisplayObjectContainer;
+ var numChildren:int = container.numChildren;
+
+ for (var i:int=0; iThis class represents the Starling version of the stage. Don't confuse it with its
+ * Flash equivalent: while the latter contains objects of the type
+ * flash.display.DisplayObject, the Starling stage contains only objects of the
+ * type starling.display.DisplayObject. Those classes are not compatible, and
+ * you cannot exchange one type with the other.
+ *
+ *
A stage object is created automatically by the Starling class. Don't
+ * create a Stage instance manually.
+ *
+ * Keyboard Events
+ *
+ *
In Starling, keyboard events are only dispatched at the stage. Add an event listener
+ * directly to the stage to be notified of keyboard events.
+ *
+ * Resize Events
+ *
+ *
When the Flash player is resized, the stage dispatches a ResizeEvent. The
+ * event contains properties containing the updated width and height of the Flash player.
+ *
+ * @see starling.events.KeyboardEvent
+ * @see starling.events.ResizeEvent
+ *
+ */
+ public class Stage extends DisplayObjectContainer
+ {
+ private var _width:int;
+ private var _height:int;
+ private var _color:uint;
+ private var _fieldOfView:Number;
+ private var _projectionOffset:Point;
+ private var _cameraPosition:Vector3D;
+ private var _enterFrameEvent:EnterFrameEvent;
+ private var _enterFrameListeners:Vector.;
+
+ // helper objects
+ private static var sMatrix:Matrix = new Matrix();
+ private static var sMatrix3D:Matrix3D = new Matrix3D();
+
+ /** @private */
+ public function Stage(width:int, height:int, color:uint=0)
+ {
+ _width = width;
+ _height = height;
+ _color = color;
+ _fieldOfView = 1.0;
+ _projectionOffset = new Point();
+ _cameraPosition = new Vector3D();
+ _enterFrameEvent = new EnterFrameEvent(Event.ENTER_FRAME, 0.0);
+ _enterFrameListeners = new [];
+ }
+
+ /** @inheritDoc */
+ public function advanceTime(passedTime:Number):void
+ {
+ _enterFrameEvent.reset(Event.ENTER_FRAME, false, passedTime);
+ broadcastEvent(_enterFrameEvent);
+ }
+
+ /** Returns the object that is found topmost beneath a point in stage coordinates, or
+ * the stage itself if nothing else is found. */
+ public override function hitTest(localPoint:Point):DisplayObject
+ {
+ if (!visible || !touchable) return null;
+
+ // locations outside of the stage area shouldn't be accepted
+ if (localPoint.x < 0 || localPoint.x > _width ||
+ localPoint.y < 0 || localPoint.y > _height)
+ return null;
+
+ // if nothing else is hit, the stage returns itself as target
+ var target:DisplayObject = super.hitTest(localPoint);
+ return target ? target : this;
+ }
+
+ /** Draws the complete stage into a BitmapData object.
+ *
+ *
If you encounter problems with transparency, start Starling in BASELINE profile
+ * (or higher). BASELINE_CONSTRAINED might not support transparency on all platforms.
+ *
+ *
+ * @param destination If you pass null, the object will be created for you.
+ * If you pass a BitmapData object, it should have the size of the
+ * back buffer (which is accessible via the respective properties
+ * on the Starling instance).
+ * @param transparent If enabled, empty areas will appear transparent; otherwise, they
+ * will be filled with the stage color.
+ */
+ public function drawToBitmapData(destination:BitmapData=null,
+ transparent:Boolean=true):BitmapData
+ {
+ var painter:Painter = Starling.painter;
+ var state:RenderState = painter.state;
+ var context:Context3D = painter.context;
+
+ if (destination == null)
+ {
+ var width:int = context.backBufferWidth;
+ var height:int = context.backBufferHeight;
+ destination = new BitmapData(width, height, transparent);
+ }
+
+ painter.pushState();
+ state.renderTarget = null;
+ state.setProjectionMatrix(0, 0, _width, _height, _width, _height, cameraPosition);
+
+ if (transparent) painter.clear();
+ else painter.clear(_color, 1);
+
+ render(painter);
+ painter.finishMeshBatch();
+
+ context.drawToBitmapData(destination);
+ context.present(); // required on some platforms to avoid flickering
+
+ painter.popState();
+ return destination;
+ }
+
+ /** Returns the stage bounds (i.e. not the bounds of its contents, but the rectangle
+ * spawned up by 'stageWidth' and 'stageHeight') in another coordinate system. */
+ public function getStageBounds(targetSpace:DisplayObject, out:Rectangle=null):Rectangle
+ {
+ if (out == null) out = new Rectangle();
+
+ out.setTo(0, 0, _width, _height);
+ getTransformationMatrix(targetSpace, sMatrix);
+
+ return RectangleUtil.getBounds(out, sMatrix, out);
+ }
+
+ // camera positioning
+
+ /** Returns the position of the camera within the local coordinate system of a certain
+ * display object. If you do not pass a space, the method returns the global position.
+ * To change the position of the camera, you can modify the properties 'fieldOfView',
+ * 'focalDistance' and 'projectionOffset'.
+ */
+ public function getCameraPosition(space:DisplayObject=null, out:Vector3D=null):Vector3D
+ {
+ getTransformationMatrix3D(space, sMatrix3D);
+
+ return MatrixUtil.transformCoords3D(sMatrix3D,
+ _width / 2 + _projectionOffset.x, _height / 2 + _projectionOffset.y,
+ -focalLength, out);
+ }
+
+ // enter frame event optimization
+
+ /** @private */
+ internal function addEnterFrameListener(listener:DisplayObject):void
+ {
+ var index:int = _enterFrameListeners.indexOf(listener);
+ if (index < 0) _enterFrameListeners[_enterFrameListeners.length] = listener;
+ }
+
+ /** @private */
+ internal function removeEnterFrameListener(listener:DisplayObject):void
+ {
+ var index:int = _enterFrameListeners.indexOf(listener);
+ if (index >= 0) _enterFrameListeners.removeAt(index);
+ }
+
+ /** @private */
+ internal override function getChildEventListeners(object:DisplayObject, eventType:String,
+ listeners:Vector.):void
+ {
+ if (eventType == Event.ENTER_FRAME && object == this)
+ {
+ for (var i:int=0, length:int=_enterFrameListeners.length; iviewPort property of the Starling object. */
+ public function get stageWidth():int { return _width; }
+ public function set stageWidth(value:int):void { _width = value; }
+
+ /** The height of the stage coordinate system. Change it to scale its contents relative
+ * to the viewPort property of the Starling object. */
+ public function get stageHeight():int { return _height; }
+ public function set stageHeight(value:int):void { _height = value; }
+
+ /** The Starling instance this stage belongs to. */
+ public function get starling():Starling
+ {
+ var instances:Vector. = Starling.all;
+ var numInstances:int = instances.length;
+
+ for (var i:int=0; iA value close to zero will look similar to an orthographic projection; a value
+ * close to PI results in a fisheye lens effect. If the field of view is set to 0 or PI,
+ * nothing is seen on the screen.
+ *
+ * @default 1.0
+ */
+ public function get fieldOfView():Number { return _fieldOfView; }
+ public function set fieldOfView(value:Number):void { _fieldOfView = value; }
+
+ /** A vector that moves the camera away from its default position in the center of the
+ * stage. Use this property to change the center of projection, i.e. the vanishing
+ * point for 3D display objects.
CAUTION: not a copy, but the actual object!
+ */
+ public function get projectionOffset():Point { return _projectionOffset; }
+ public function set projectionOffset(value:Point):void
+ {
+ _projectionOffset.setTo(value.x, value.y);
+ }
+
+ /** The global position of the camera. This property can only be used to find out the
+ * current position, but not to modify it. For that, use the 'projectionOffset',
+ * 'fieldOfView' and 'focalLength' properties. If you need the camera position in
+ * a certain coordinate space, use 'getCameraPosition' instead.
+ *
+ *
CAUTION: not a copy, but the actual object!
+ */
+ public function get cameraPosition():Vector3D
+ {
+ return getCameraPosition(null, _cameraPosition);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/errors/AbstractClassError.as b/mobile_version/src/starling/errors/AbstractClassError.as
new file mode 100644
index 00000000..a9168935
--- /dev/null
+++ b/mobile_version/src/starling/errors/AbstractClassError.as
@@ -0,0 +1,23 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.errors
+{
+ /** An AbstractClassError is thrown when you attempt to create an instance of an abstract
+ * class. */
+ public class AbstractClassError extends Error
+ {
+ /** Creates a new AbstractClassError object. */
+ public function AbstractClassError(message:*="Cannot instantiate abstract class", id:*=0)
+ {
+ super(message, id);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/errors/AbstractMethodError.as b/mobile_version/src/starling/errors/AbstractMethodError.as
new file mode 100644
index 00000000..3206babe
--- /dev/null
+++ b/mobile_version/src/starling/errors/AbstractMethodError.as
@@ -0,0 +1,22 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.errors
+{
+ /** An AbstractMethodError is thrown when you attempt to call an abstract method. */
+ public class AbstractMethodError extends Error
+ {
+ /** Creates a new AbstractMethodError object. */
+ public function AbstractMethodError(message:*="Method needs to be implemented in subclass", id:*=0)
+ {
+ super(message, id);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/errors/MissingContextError.as b/mobile_version/src/starling/errors/MissingContextError.as
new file mode 100644
index 00000000..114735ee
--- /dev/null
+++ b/mobile_version/src/starling/errors/MissingContextError.as
@@ -0,0 +1,23 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.errors
+{
+ /** A MissingContextError is thrown when a Context3D object is required but not (yet)
+ * available. */
+ public class MissingContextError extends Error
+ {
+ /** Creates a new MissingContextError object. */
+ public function MissingContextError(message:*="Starling context is missing", id:*=0)
+ {
+ super(message, id);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/errors/NotSupportedError.as b/mobile_version/src/starling/errors/NotSupportedError.as
new file mode 100644
index 00000000..abfacdf6
--- /dev/null
+++ b/mobile_version/src/starling/errors/NotSupportedError.as
@@ -0,0 +1,23 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.errors
+{
+ /** A NotSupportedError is thrown when you attempt to use a feature that is not supported
+ * on the current platform. */
+ public class NotSupportedError extends Error
+ {
+ /** Creates a new NotSupportedError object. */
+ public function NotSupportedError(message:* = "", id:* = 0)
+ {
+ super(message, id);
+ }
+ }
+}
diff --git a/mobile_version/src/starling/events/EnterFrameEvent.as b/mobile_version/src/starling/events/EnterFrameEvent.as
new file mode 100644
index 00000000..de605a0f
--- /dev/null
+++ b/mobile_version/src/starling/events/EnterFrameEvent.as
@@ -0,0 +1,34 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ /** An EnterFrameEvent is triggered once per frame and is dispatched to all objects in the
+ * display tree.
+ *
+ * It contains information about the time that has passed since the last frame. That way, you
+ * can easily make animations that are independent of the frame rate, taking the passed time
+ * into account.
+ */
+ public class EnterFrameEvent extends Event
+ {
+ /** Event type for a display object that is entering a new frame. */
+ public static const ENTER_FRAME:String = "enterFrame";
+
+ /** Creates an enter frame event with the passed time. */
+ public function EnterFrameEvent(type:String, passedTime:Number, bubbles:Boolean=false)
+ {
+ super(type, bubbles, passedTime);
+ }
+
+ /** The time that has passed since the last frame (in seconds). */
+ public function get passedTime():Number { return data as Number; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/Event.as b/mobile_version/src/starling/events/Event.as
new file mode 100644
index 00000000..395d22b8
--- /dev/null
+++ b/mobile_version/src/starling/events/Event.as
@@ -0,0 +1,190 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.utils.getQualifiedClassName;
+
+ import starling.core.starling_internal;
+ import starling.utils.StringUtil;
+
+ use namespace starling_internal;
+
+ /** Event objects are passed as parameters to event listeners when an event occurs.
+ * This is Starling's version of the Flash Event class.
+ *
+ *
EventDispatchers create instances of this class and send them to registered listeners.
+ * An event object contains information that characterizes an event, most importantly the
+ * event type and if the event bubbles. The target of an event is the object that
+ * dispatched it.
+ *
+ *
For some event types, this information is sufficient; other events may need additional
+ * information to be carried to the listener. In that case, you can subclass "Event" and add
+ * properties with all the information you require. The "EnterFrameEvent" is an example for
+ * this practice; it adds a property about the time that has passed since the last frame.
+ *
+ *
Furthermore, the event class contains methods that can stop the event from being
+ * processed by other listeners - either completely or at the next bubble stage.
+ *
+ * @see EventDispatcher
+ */
+ public class Event
+ {
+ /** Event type for a display object that is added to a parent. */
+ public static const ADDED:String = "added";
+ /** Event type for a display object that is added to the stage */
+ public static const ADDED_TO_STAGE:String = "addedToStage";
+ /** Event type for a display object that is entering a new frame. */
+ public static const ENTER_FRAME:String = "enterFrame";
+ /** Event type for a display object that is removed from its parent. */
+ public static const REMOVED:String = "removed";
+ /** Event type for a display object that is removed from the stage. */
+ public static const REMOVED_FROM_STAGE:String = "removedFromStage";
+ /** Event type for a triggered button. */
+ public static const TRIGGERED:String = "triggered";
+ /** Event type for a resized Flash Player. */
+ public static const RESIZE:String = "resize";
+ /** Event type that may be used whenever something finishes. */
+ public static const COMPLETE:String = "complete";
+ /** Event type for a (re)created stage3D rendering context. */
+ public static const CONTEXT3D_CREATE:String = "context3DCreate";
+ /** Event type that is dispatched by the Starling instance directly before rendering. */
+ public static const RENDER:String = "render";
+ /** Event type that indicates that the root DisplayObject has been created. */
+ public static const ROOT_CREATED:String = "rootCreated";
+ /** Event type for an animated object that requests to be removed from the juggler. */
+ public static const REMOVE_FROM_JUGGLER:String = "removeFromJuggler";
+ /** Event type that is dispatched by the AssetManager after a context loss. */
+ public static const TEXTURES_RESTORED:String = "texturesRestored";
+ /** Event type that is dispatched by the AssetManager when a file/url cannot be loaded. */
+ public static const IO_ERROR:String = "ioError";
+ /** Event type that is dispatched by the AssetManager when a file/url cannot be loaded. */
+ public static const SECURITY_ERROR:String = "securityError";
+ /** Event type that is dispatched by the AssetManager when an xml or json file couldn't
+ * be parsed. */
+ public static const PARSE_ERROR:String = "parseError";
+ /** Event type that is dispatched by the Starling instance when it encounters a problem
+ * from which it cannot recover, e.g. a lost device context. */
+ public static const FATAL_ERROR:String = "fatalError";
+
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const CHANGE:String = "change";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const CANCEL:String = "cancel";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const SCROLL:String = "scroll";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const OPEN:String = "open";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const CLOSE:String = "close";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const SELECT:String = "select";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const READY:String = "ready";
+ /** An event type to be utilized in custom events. Not used by Starling right now. */
+ public static const UPDATE:String = "update";
+
+ private static var sEventPool:Vector. = new [];
+
+ private var _target:EventDispatcher;
+ private var _currentTarget:EventDispatcher;
+ private var _type:String;
+ private var _bubbles:Boolean;
+ private var _stopsPropagation:Boolean;
+ private var _stopsImmediatePropagation:Boolean;
+ private var _data:Object;
+
+ /** Creates an event object that can be passed to listeners. */
+ public function Event(type:String, bubbles:Boolean=false, data:Object=null)
+ {
+ _type = type;
+ _bubbles = bubbles;
+ _data = data;
+ }
+
+ /** Prevents listeners at the next bubble stage from receiving the event. */
+ public function stopPropagation():void
+ {
+ _stopsPropagation = true;
+ }
+
+ /** Prevents any other listeners from receiving the event. */
+ public function stopImmediatePropagation():void
+ {
+ _stopsPropagation = _stopsImmediatePropagation = true;
+ }
+
+ /** Returns a description of the event, containing type and bubble information. */
+ public function toString():String
+ {
+ return StringUtil.format("[{0} type=\"{1}\" bubbles={2}]",
+ getQualifiedClassName(this).split("::").pop(), _type, _bubbles);
+ }
+
+ /** Indicates if event will bubble. */
+ public function get bubbles():Boolean { return _bubbles; }
+
+ /** The object that dispatched the event. */
+ public function get target():EventDispatcher { return _target; }
+
+ /** The object the event is currently bubbling at. */
+ public function get currentTarget():EventDispatcher { return _currentTarget; }
+
+ /** A string that identifies the event. */
+ public function get type():String { return _type; }
+
+ /** Arbitrary data that is attached to the event. */
+ public function get data():Object { return _data; }
+
+ // properties for internal use
+
+ /** @private */
+ internal function setTarget(value:EventDispatcher):void { _target = value; }
+
+ /** @private */
+ internal function setCurrentTarget(value:EventDispatcher):void { _currentTarget = value; }
+
+ /** @private */
+ internal function setData(value:Object):void { _data = value; }
+
+ /** @private */
+ internal function get stopsPropagation():Boolean { return _stopsPropagation; }
+
+ /** @private */
+ internal function get stopsImmediatePropagation():Boolean { return _stopsImmediatePropagation; }
+
+ // event pooling
+
+ /** @private */
+ starling_internal static function fromPool(type:String, bubbles:Boolean=false, data:Object=null):Event
+ {
+ if (sEventPool.length) return sEventPool.pop().reset(type, bubbles, data);
+ else return new Event(type, bubbles, data);
+ }
+
+ /** @private */
+ starling_internal static function toPool(event:Event):void
+ {
+ event._data = event._target = event._currentTarget = null;
+ sEventPool[sEventPool.length] = event; // avoiding 'push'
+ }
+
+ /** @private */
+ starling_internal function reset(type:String, bubbles:Boolean=false, data:Object=null):Event
+ {
+ _type = type;
+ _bubbles = bubbles;
+ _data = data;
+ _target = _currentTarget = null;
+ _stopsPropagation = _stopsImmediatePropagation = false;
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/EventDispatcher.as b/mobile_version/src/starling/events/EventDispatcher.as
new file mode 100644
index 00000000..fad3f714
--- /dev/null
+++ b/mobile_version/src/starling/events/EventDispatcher.as
@@ -0,0 +1,215 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.utils.Dictionary;
+
+ import starling.core.starling_internal;
+ import starling.display.DisplayObject;
+
+ use namespace starling_internal;
+
+ /** The EventDispatcher class is the base class for all classes that dispatch events.
+ * This is the Starling version of the Flash class with the same name.
+ *
+ *
The event mechanism is a key feature of Starling's architecture. Objects can communicate
+ * with each other through events. Compared the the Flash event system, Starling's event system
+ * was simplified. The main difference is that Starling events have no "Capture" phase.
+ * They are simply dispatched at the target and may optionally bubble up. They cannot move
+ * in the opposite direction.
+ *
+ *
As in the conventional Flash classes, display objects inherit from EventDispatcher
+ * and can thus dispatch events. Beware, though, that the Starling event classes are
+ * not compatible with Flash events: Starling display objects dispatch
+ * Starling events, which will bubble along Starling display objects - but they cannot
+ * dispatch Flash events or bubble along Flash display objects.
+ *
+ * @see Event
+ * @see starling.display.DisplayObject DisplayObject
+ */
+ public class EventDispatcher
+ {
+ private var _eventListeners:Dictionary;
+
+ /** Helper object. */
+ private static var sBubbleChains:Array = [];
+
+ /** Creates an EventDispatcher. */
+ public function EventDispatcher()
+ { }
+
+ /** Registers an event listener at a certain object. */
+ public function addEventListener(type:String, listener:Function):void
+ {
+ if (_eventListeners == null)
+ _eventListeners = new Dictionary();
+
+ var listeners:Vector. = _eventListeners[type] as Vector.;
+ if (listeners == null)
+ _eventListeners[type] = new [listener];
+ else if (listeners.indexOf(listener) == -1) // check for duplicates
+ listeners[listeners.length] = listener; // avoid 'push'
+ }
+
+ /** Removes an event listener from the object. */
+ public function removeEventListener(type:String, listener:Function):void
+ {
+ if (_eventListeners)
+ {
+ var listeners:Vector. = _eventListeners[type] as Vector.;
+ var numListeners:int = listeners ? listeners.length : 0;
+
+ if (numListeners > 0)
+ {
+ // we must not modify the original vector, but work on a copy.
+ // (see comment in 'invokeEvent')
+
+ var index:int = listeners.indexOf(listener);
+
+ if (index != -1)
+ {
+ var restListeners:Vector. = listeners.slice(0, index);
+
+ for (var i:int=index+1; i = _eventListeners ?
+ _eventListeners[event.type] as Vector. : null;
+ var numListeners:int = listeners == null ? 0 : listeners.length;
+
+ if (numListeners)
+ {
+ event.setCurrentTarget(this);
+
+ // we can enumerate directly over the vector, because:
+ // when somebody modifies the list while we're looping, "addEventListener" is not
+ // problematic, and "removeEventListener" will create a new Vector, anyway.
+
+ for (var i:int=0; i;
+ var element:DisplayObject = this as DisplayObject;
+ var length:int = 1;
+
+ if (sBubbleChains.length > 0) { chain = sBubbleChains.pop(); chain[0] = element; }
+ else chain = new [element];
+
+ while ((element = element.parent) != null)
+ chain[int(length++)] = element;
+
+ for (var i:int=0; i = _eventListeners ? _eventListeners[type] : null;
+ if (listeners == null) return false;
+ else
+ {
+ if (listener != null) return listeners.indexOf(listener) != -1;
+ else return listeners.length != 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/KeyboardEvent.as b/mobile_version/src/starling/events/KeyboardEvent.as
new file mode 100644
index 00000000..7c388ce9
--- /dev/null
+++ b/mobile_version/src/starling/events/KeyboardEvent.as
@@ -0,0 +1,88 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ /** A KeyboardEvent is dispatched in response to user input through a keyboard.
+ *
+ *
This is Starling's version of the Flash KeyboardEvent class. It contains the same
+ * properties as the Flash equivalent.
+ *
+ *
To be notified of keyboard events, add an event listener to any display object that
+ * is part of your display tree. Starling has no concept of a "Focus" like native Flash.
+ *
+ * @see starling.display.Stage
+ */
+ public class KeyboardEvent extends Event
+ {
+ /** Event type for a key that was released. */
+ public static const KEY_UP:String = "keyUp";
+
+ /** Event type for a key that was pressed. */
+ public static const KEY_DOWN:String = "keyDown";
+
+ private var _charCode:uint;
+ private var _keyCode:uint;
+ private var _keyLocation:uint;
+ private var _altKey:Boolean;
+ private var _ctrlKey:Boolean;
+ private var _shiftKey:Boolean;
+ private var _isDefaultPrevented:Boolean;
+
+ /** Creates a new KeyboardEvent. */
+ public function KeyboardEvent(type:String, charCode:uint=0, keyCode:uint=0,
+ keyLocation:uint=0, ctrlKey:Boolean=false,
+ altKey:Boolean=false, shiftKey:Boolean=false)
+ {
+ super(type, false, keyCode);
+ _charCode = charCode;
+ _keyCode = keyCode;
+ _keyLocation = keyLocation;
+ _ctrlKey = ctrlKey;
+ _altKey = altKey;
+ _shiftKey = shiftKey;
+ }
+
+ // prevent default
+
+ /** Cancels the keyboard event's default behavior. This will be forwarded to the native
+ * flash KeyboardEvent. */
+ public function preventDefault():void
+ {
+ _isDefaultPrevented = true;
+ }
+
+ /** Checks whether the preventDefault() method has been called on the event. */
+ public function isDefaultPrevented():Boolean { return _isDefaultPrevented; }
+
+ // properties
+
+ /** Contains the character code of the key. */
+ public function get charCode():uint { return _charCode; }
+
+ /** The key code of the key. */
+ public function get keyCode():uint { return _keyCode; }
+
+ /** Indicates the location of the key on the keyboard. This is useful for differentiating
+ * keys that appear more than once on a keyboard. @see Keylocation */
+ public function get keyLocation():uint { return _keyLocation; }
+
+ /** Indicates whether the Alt key is active on Windows or Linux;
+ * indicates whether the Option key is active on Mac OS. */
+ public function get altKey():Boolean { return _altKey; }
+
+ /** Indicates whether the Ctrl key is active on Windows or Linux;
+ * indicates whether either the Ctrl or the Command key is active on Mac OS. */
+ public function get ctrlKey():Boolean { return _ctrlKey; }
+
+ /** Indicates whether the Shift key modifier is active (true) or inactive (false). */
+ public function get shiftKey():Boolean { return _shiftKey; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/ResizeEvent.as b/mobile_version/src/starling/events/ResizeEvent.as
new file mode 100644
index 00000000..8f4162b7
--- /dev/null
+++ b/mobile_version/src/starling/events/ResizeEvent.as
@@ -0,0 +1,44 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.geom.Point;
+
+ /** A ResizeEvent is dispatched by the stage when the size of the Flash container changes.
+ * Use it to update the Starling viewport and the stage size.
+ *
+ *
The event contains properties containing the updated width and height of the Flash
+ * player. If you want to scale the contents of your stage to fill the screen, update the
+ * Starling.current.viewPort rectangle accordingly. If you want to make use of
+ * the additional screen estate, update the values of stage.stageWidth and
+ * stage.stageHeight as well.
+ *
+ * @see starling.display.Stage
+ * @see starling.core.Starling
+ */
+ public class ResizeEvent extends Event
+ {
+ /** Event type for a resized Flash player. */
+ public static const RESIZE:String = "resize";
+
+ /** Creates a new ResizeEvent. */
+ public function ResizeEvent(type:String, width:int, height:int, bubbles:Boolean=false)
+ {
+ super(type, bubbles, new Point(width, height));
+ }
+
+ /** The updated width of the player. */
+ public function get width():int { return (data as Point).x; }
+
+ /** The updated height of the player. */
+ public function get height():int { return (data as Point).y; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/Touch.as b/mobile_version/src/starling/events/Touch.as
new file mode 100644
index 00000000..f8fd139d
--- /dev/null
+++ b/mobile_version/src/starling/events/Touch.as
@@ -0,0 +1,240 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.geom.Point;
+
+ import starling.display.DisplayObject;
+ import starling.utils.StringUtil;
+
+ /** A Touch object contains information about the presence or movement of a finger
+ * or the mouse on the screen.
+ *
+ *
You receive objects of this type from a TouchEvent. When such an event is triggered,
+ * you can query it for all touches that are currently present on the screen. One touch
+ * object contains information about a single touch; it always transitions through a series
+ * of TouchPhases. Have a look at the TouchPhase class for more information.
+ *
+ * The position of a touch
+ *
+ *
You can get the current and previous position in stage coordinates with the corresponding
+ * properties. However, you'll want to have the position in a different coordinate system
+ * most of the time. For this reason, there are methods that convert the current and previous
+ * touches into the local coordinate system of any object.
+ *
+ * @see TouchEvent
+ * @see TouchPhase
+ */
+ public class Touch
+ {
+ private var _id:int;
+ private var _globalX:Number;
+ private var _globalY:Number;
+ private var _previousGlobalX:Number;
+ private var _previousGlobalY:Number;
+ private var _tapCount:int;
+ private var _phase:String;
+ private var _target:DisplayObject;
+ private var _timestamp:Number;
+ private var _pressure:Number;
+ private var _width:Number;
+ private var _height:Number;
+ private var _cancelled:Boolean;
+ private var _bubbleChain:Vector.;
+
+ /** Helper object. */
+ private static var sHelperPoint:Point = new Point();
+
+ /** Creates a new Touch object. */
+ public function Touch(id:int)
+ {
+ _id = id;
+ _tapCount = 0;
+ _phase = TouchPhase.HOVER;
+ _pressure = _width = _height = 1.0;
+ _bubbleChain = new [];
+ }
+
+ /** Converts the current location of a touch to the local coordinate system of a display
+ * object. If you pass an out-point, the result will be stored in this point
+ * instead of creating a new object.*/
+ public function getLocation(space:DisplayObject, out:Point=null):Point
+ {
+ sHelperPoint.setTo(_globalX, _globalY);
+ return space.globalToLocal(sHelperPoint, out);
+ }
+
+ /** Converts the previous location of a touch to the local coordinate system of a display
+ * object. If you pass an out-point, the result will be stored in this point
+ * instead of creating a new object.*/
+ public function getPreviousLocation(space:DisplayObject, out:Point=null):Point
+ {
+ sHelperPoint.setTo(_previousGlobalX, _previousGlobalY);
+ return space.globalToLocal(sHelperPoint, out);
+ }
+
+ /** Returns the movement of the touch between the current and previous location.
+ * If you pass an out-point, the result will be stored in this point instead
+ * of creating a new object. */
+ public function getMovement(space:DisplayObject, out:Point=null):Point
+ {
+ if (out == null) out = new Point();
+ getLocation(space, out);
+ var x:Number = out.x;
+ var y:Number = out.y;
+ getPreviousLocation(space, out);
+ out.setTo(x - out.x, y - out.y);
+ return out;
+ }
+
+ /** Indicates if the target or one of its children is touched. */
+ public function isTouching(target:DisplayObject):Boolean
+ {
+ return _bubbleChain.indexOf(target) != -1;
+ }
+
+ /** Returns a description of the object. */
+ public function toString():String
+ {
+ return StringUtil.format("[Touch {0}: globalX={1}, globalY={2}, phase={3}]",
+ _id, _globalX, _globalY, _phase);
+ }
+
+ /** Creates a clone of the Touch object. */
+ public function clone():Touch
+ {
+ var clone:Touch = new Touch(_id);
+ clone._globalX = _globalX;
+ clone._globalY = _globalY;
+ clone._previousGlobalX = _previousGlobalX;
+ clone._previousGlobalY = _previousGlobalY;
+ clone._phase = _phase;
+ clone._tapCount = _tapCount;
+ clone._timestamp = _timestamp;
+ clone._pressure = _pressure;
+ clone._width = _width;
+ clone._height = _height;
+ clone._cancelled = _cancelled;
+ clone.target = _target;
+ return clone;
+ }
+
+ // helper methods
+
+ private function updateBubbleChain():void
+ {
+ if (_target)
+ {
+ var length:int = 1;
+ var element:DisplayObject = _target;
+
+ _bubbleChain.length = 1;
+ _bubbleChain[0] = element;
+
+ while ((element = element.parent) != null)
+ _bubbleChain[int(length++)] = element;
+ }
+ else
+ {
+ _bubbleChain.length = 0;
+ }
+ }
+
+ // properties
+
+ /** The identifier of a touch. '0' for mouse events, an increasing number for touches. */
+ public function get id():int { return _id; }
+
+ /** The previous x-position of the touch in stage coordinates. */
+ public function get previousGlobalX():Number { return _previousGlobalX; }
+
+ /** The previous y-position of the touch in stage coordinates. */
+ public function get previousGlobalY():Number { return _previousGlobalY; }
+
+ /** The x-position of the touch in stage coordinates. If you change this value,
+ * the previous one will be moved to "previousGlobalX". */
+ public function get globalX():Number { return _globalX; }
+ public function set globalX(value:Number):void
+ {
+ _previousGlobalX = _globalX != _globalX ? value : _globalX; // isNaN check
+ _globalX = value;
+ }
+
+ /** The y-position of the touch in stage coordinates. If you change this value,
+ * the previous one will be moved to "previousGlobalY". */
+ public function get globalY():Number { return _globalY; }
+ public function set globalY(value:Number):void
+ {
+ _previousGlobalY = _globalY != _globalY ? value : _globalY; // isNaN check
+ _globalY = value;
+ }
+
+ /** The number of taps the finger made in a short amount of time. Use this to detect
+ * double-taps / double-clicks, etc. */
+ public function get tapCount():int { return _tapCount; }
+ public function set tapCount(value:int):void { _tapCount = value; }
+
+ /** The current phase the touch is in. @see TouchPhase */
+ public function get phase():String { return _phase; }
+ public function set phase(value:String):void { _phase = value; }
+
+ /** The display object at which the touch occurred. */
+ public function get target():DisplayObject { return _target; }
+ public function set target(value:DisplayObject):void
+ {
+ if (_target != value)
+ {
+ _target = value;
+ updateBubbleChain();
+ }
+ }
+
+ /** The moment the touch occurred (in seconds since application start). */
+ public function get timestamp():Number { return _timestamp; }
+ public function set timestamp(value:Number):void { _timestamp = value; }
+
+ /** A value between 0.0 and 1.0 indicating force of the contact with the device.
+ * If the device does not support detecting the pressure, the value is 1.0. */
+ public function get pressure():Number { return _pressure; }
+ public function set pressure(value:Number):void { _pressure = value; }
+
+ /** Width of the contact area.
+ * If the device does not support detecting the pressure, the value is 1.0. */
+ public function get width():Number { return _width; }
+ public function set width(value:Number):void { _width = value; }
+
+ /** Height of the contact area.
+ * If the device does not support detecting the pressure, the value is 1.0. */
+ public function get height():Number { return _height; }
+ public function set height(value:Number):void { _height = value; }
+
+ /** Indicates if the touch has been cancelled, which may happen when the app moves into
+ * the background ('Event.DEACTIVATE'). @default false */
+ public function get cancelled():Boolean { return _cancelled; }
+ public function set cancelled(value:Boolean):void { _cancelled = value; }
+
+ // internal methods
+
+ /** @private
+ * Dispatches a touch event along the current bubble chain (which is updated each time
+ * a target is set). */
+ internal function dispatchEvent(event:TouchEvent):void
+ {
+ if (_target) event.dispatch(_bubbleChain);
+ }
+
+ /** @private */
+ internal function get bubbleChain():Vector.
+ {
+ return _bubbleChain.concat();
+ }
+ }
+}
diff --git a/mobile_version/src/starling/events/TouchEvent.as b/mobile_version/src/starling/events/TouchEvent.as
new file mode 100644
index 00000000..613c4071
--- /dev/null
+++ b/mobile_version/src/starling/events/TouchEvent.as
@@ -0,0 +1,218 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import starling.core.starling_internal;
+ import starling.display.DisplayObject;
+
+ use namespace starling_internal;
+
+ /** A TouchEvent is triggered either by touch or mouse input.
+ *
+ *
In Starling, both touch events and mouse events are handled through the same class:
+ * TouchEvent. To process user input from a touch screen or the mouse, you have to register
+ * an event listener for events of the type TouchEvent.TOUCH. This is the only
+ * event type you need to handle; the long list of mouse event types as they are used in
+ * conventional Flash are mapped to so-called "TouchPhases" instead.
+ *
+ *
The difference between mouse input and touch input is that
+ *
+ *
+ *
only one mouse cursor can be present at a given moment and
+ *
only the mouse can "hover" over an object without a pressed button.
In Starling, any display object receives touch events, as long as the
+ * touchable property of the object and its parents is enabled. There
+ * is no "InteractiveObject" class in Starling.
+ *
+ * How to work with individual touches
+ *
+ *
The event contains a list of all touches that are currently present. Each individual
+ * touch is stored in an object of type "Touch". Since you are normally only interested in
+ * the touches that occurred on top of certain objects, you can query the event for touches
+ * with a specific target:
This will return all touches of "this" or one of its children. When you are not using
+ * multitouch, you can also access the touch object directly, like this:
+ *
+ * var touch:Touch = touchEvent.getTouch(this);
+ *
+ * @see Touch
+ * @see TouchPhase
+ */
+ public class TouchEvent extends Event
+ {
+ /** Event type for touch or mouse input. */
+ public static const TOUCH:String = "touch";
+
+ private var _shiftKey:Boolean;
+ private var _ctrlKey:Boolean;
+ private var _timestamp:Number;
+ private var _visitedObjects:Vector.;
+
+ /** Helper object. */
+ private static var sTouches:Vector. = new [];
+
+ /** Creates a new TouchEvent instance. */
+ public function TouchEvent(type:String, touches:Vector.=null, shiftKey:Boolean=false,
+ ctrlKey:Boolean=false, bubbles:Boolean=true)
+ {
+ super(type, bubbles, touches);
+
+ _shiftKey = shiftKey;
+ _ctrlKey = ctrlKey;
+ _visitedObjects = new [];
+
+ updateTimestamp(touches);
+ }
+
+ /** @private */
+ internal function resetTo(type:String, touches:Vector.=null, shiftKey:Boolean=false,
+ ctrlKey:Boolean=false, bubbles:Boolean=true):TouchEvent
+ {
+ super.reset(type, bubbles, touches);
+
+ _shiftKey = shiftKey;
+ _ctrlKey = ctrlKey;
+ _visitedObjects.length = 0;
+ updateTimestamp(touches);
+
+ return this;
+ }
+
+ private function updateTimestamp(touches:Vector.):void
+ {
+ _timestamp = -1.0;
+ var numTouches:int = touches ? touches.length : 0;
+
+ for (var i:int=0; i _timestamp)
+ _timestamp = touches[i].timestamp;
+ }
+
+ /** Returns a list of touches that originated over a certain target. If you pass an
+ * out-vector, the touches will be added to this vector instead of creating
+ * a new object. */
+ public function getTouches(target:DisplayObject, phase:String=null,
+ out:Vector.=null):Vector.
+ {
+ if (out == null) out = new [];
+ var allTouches:Vector. = data as Vector.;
+ var numTouches:int = allTouches.length;
+
+ for (var i:int=0; i 0)
+ {
+ var touch:Touch = null;
+
+ if (id < 0) touch = sTouches[0];
+ else
+ {
+ for (var i:int=0; i=0; --i)
+ {
+ if (sTouches[i].phase != TouchPhase.ENDED)
+ {
+ result = true;
+ break;
+ }
+ }
+
+ sTouches.length = 0;
+ return result;
+ }
+
+ // custom dispatching
+
+ /** @private
+ * Dispatches the event along a custom bubble chain. During the lifetime of the event,
+ * each object is visited only once. */
+ internal function dispatch(chain:Vector.):void
+ {
+ if (chain && chain.length)
+ {
+ var chainLength:int = bubbles ? chain.length : 1;
+ var previousTarget:EventDispatcher = target;
+ setTarget(chain[0] as EventDispatcher);
+
+ for (var i:int=0; i { return (data as Vector.).concat(); }
+
+ /** Indicates if the shift key was pressed when the event occurred. */
+ public function get shiftKey():Boolean { return _shiftKey; }
+
+ /** Indicates if the ctrl key was pressed when the event occurred. (Mac OS: Cmd or Ctrl) */
+ public function get ctrlKey():Boolean { return _ctrlKey; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/TouchMarker.as b/mobile_version/src/starling/events/TouchMarker.as
new file mode 100644
index 00000000..df3ff940
--- /dev/null
+++ b/mobile_version/src/starling/events/TouchMarker.as
@@ -0,0 +1,104 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.display.BitmapData;
+ import flash.display.Shape;
+ import flash.geom.Point;
+
+ import starling.core.Starling;
+ import starling.display.Image;
+ import starling.display.Sprite;
+ import starling.textures.Texture;
+
+ /** The TouchMarker is used internally to mark touches created through "simulateMultitouch". */
+ internal class TouchMarker extends Sprite
+ {
+ private var _center:Point;
+ private var _texture:Texture;
+
+ public function TouchMarker()
+ {
+ _center = new Point();
+ _texture = createTexture();
+
+ for (var i:int=0; i<2; ++i)
+ {
+ var marker:Image = new Image(_texture);
+ marker.pivotX = _texture.width / 2;
+ marker.pivotY = _texture.height / 2;
+ marker.touchable = false;
+ addChild(marker);
+ }
+ }
+
+ public override function dispose():void
+ {
+ _texture.dispose();
+ super.dispose();
+ }
+
+ public function moveMarker(x:Number, y:Number, withCenter:Boolean=false):void
+ {
+ if (withCenter)
+ {
+ _center.x += x - realMarker.x;
+ _center.y += y - realMarker.y;
+ }
+
+ realMarker.x = x;
+ realMarker.y = y;
+ mockMarker.x = 2*_center.x - x;
+ mockMarker.y = 2*_center.y - y;
+ }
+
+ public function moveCenter(x:Number, y:Number):void
+ {
+ _center.x = x;
+ _center.y = y;
+ moveMarker(realX, realY); // reset mock position
+ }
+
+ private function createTexture():Texture
+ {
+ var scale:Number = Starling.contentScaleFactor;
+ var radius:Number = 12 * scale;
+ var width:int = 32 * scale;
+ var height:int = 32 * scale;
+ var thickness:Number = 1.5 * scale;
+ var shape:Shape = new Shape();
+
+ // draw dark outline
+ shape.graphics.lineStyle(thickness, 0x0, 0.3);
+ shape.graphics.drawCircle(width/2, height/2, radius + thickness);
+
+ // draw white inner circle
+ shape.graphics.beginFill(0xffffff, 0.4);
+ shape.graphics.lineStyle(thickness, 0xffffff);
+ shape.graphics.drawCircle(width/2, height/2, radius);
+ shape.graphics.endFill();
+
+ var bmpData:BitmapData = new BitmapData(width, height, true, 0x0);
+ bmpData.draw(shape);
+
+ return Texture.fromBitmapData(bmpData, false, false, scale);
+ }
+
+ private function get realMarker():Image { return getChildAt(0) as Image; }
+ private function get mockMarker():Image { return getChildAt(1) as Image; }
+
+ public function get realX():Number { return realMarker.x; }
+ public function get realY():Number { return realMarker.y; }
+
+ public function get mockX():Number { return mockMarker.x; }
+ public function get mockY():Number { return mockMarker.y; }
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/TouchPhase.as b/mobile_version/src/starling/events/TouchPhase.as
new file mode 100644
index 00000000..2749a8ae
--- /dev/null
+++ b/mobile_version/src/starling/events/TouchPhase.as
@@ -0,0 +1,53 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import starling.errors.AbstractClassError;
+
+ /** A class that provides constant values for the phases of a touch object.
+ *
+ *
A touch moves through at least the following phases in its life:
+ *
+ * BEGAN -> MOVED -> ENDED
+ *
+ *
Furthermore, a touch can enter a STATIONARY phase. That phase does not
+ * trigger a touch event itself, and it can only occur in multitouch environments. Picture a
+ * situation where one finger is moving and the other is stationary. A touch event will
+ * be dispatched only to the object under the moving finger. In the list of touches
+ * of that event, you will find the second touch in the stationary phase.
+ *
+ *
Finally, there's the HOVER phase, which is exclusive to mouse input. It is
+ * the equivalent of a MouseOver event in Flash when the mouse button is
+ * not pressed.
+ */
+ public final class TouchPhase
+ {
+ /** @private */
+ public function TouchPhase() { throw new AbstractClassError(); }
+
+ /** Only available for mouse input: the cursor hovers over an object without a
+ * pressed button. */
+ public static const HOVER:String = "hover";
+
+ /** The finger touched the screen just now, or the mouse button was pressed. */
+ public static const BEGAN:String = "began";
+
+ /** The finger moves around on the screen, or the mouse is moved while the button is
+ * pressed. */
+ public static const MOVED:String = "moved";
+
+ /** The finger or mouse (with pressed button) has not moved since the last frame. */
+ public static const STATIONARY:String = "stationary";
+
+ /** The finger was lifted from the screen or from the mouse button. */
+ public static const ENDED:String = "ended";
+ }
+}
\ No newline at end of file
diff --git a/mobile_version/src/starling/events/TouchProcessor.as b/mobile_version/src/starling/events/TouchProcessor.as
new file mode 100644
index 00000000..76ff3751
--- /dev/null
+++ b/mobile_version/src/starling/events/TouchProcessor.as
@@ -0,0 +1,481 @@
+// =================================================================================================
+//
+// Starling Framework
+// Copyright Gamua GmbH. All Rights Reserved.
+//
+// This program is free software. You can redistribute and/or modify it
+// in accordance with the terms of the accompanying license agreement.
+//
+// =================================================================================================
+
+package starling.events
+{
+ import flash.geom.Point;
+ import flash.utils.getDefinitionByName;
+
+ import starling.core.Starling;
+ import starling.display.DisplayObject;
+ import starling.display.Stage;
+
+ /** The TouchProcessor is used to convert mouse and touch events of the conventional
+ * Flash stage to Starling's TouchEvents.
+ *
+ *
The Starling instance listens to mouse and touch events on the native stage. The
+ * attributes of those events are enqueued (right as they are happening) in the
+ * TouchProcessor.
+ *
+ *
Once per frame, the "advanceTime" method is called. It analyzes the touch queue and
+ * figures out which touches are active at that moment; the properties of all touch objects
+ * are updated accordingly.
+ *
+ *
Once the list of touches has been finalized, the "processTouches" method is called
+ * (that might happen several times in one "advanceTime" execution; no information is
+ * discarded). It's responsible for dispatching the actual touch events to the Starling
+ * display tree.
+ *
+ * Subclassing TouchProcessor
+ *
+ *
You can extend the TouchProcessor if you need to have more control over touch and
+ * mouse input. For example, you could filter the touches by overriding the "processTouches"
+ * method, throwing away any touches you're not interested in and passing the rest to the
+ * super implementation.
+ *
+ *
To use your custom TouchProcessor, assign it to the "Starling.touchProcessor"
+ * property.
+ *
+ *
Note that you should not dispatch TouchEvents yourself, since they are
+ * much more complex to handle than conventional events (e.g. it must be made sure that an
+ * object receives a TouchEvent only once, even if it's manipulated with several fingers).
+ * Always use the base implementation of "processTouches" to let them be dispatched. That
+ * said: you can always dispatch your own custom events, of course.
+ */
+ public class TouchProcessor
+ {
+ private var _stage:Stage;
+ private var _root:DisplayObject;
+ private var _elapsedTime:Number;
+ private var _lastTaps:Vector.;
+ private var _shiftDown:Boolean = false;
+ private var _ctrlDown:Boolean = false;
+ private var _multitapTime:Number = 0.3;
+ private var _multitapDistance:Number = 25;
+ private var _touchEvent:TouchEvent;
+
+ private var _touchMarker:TouchMarker;
+ private var _simulateMultitouch:Boolean;
+
+ /** A vector of arrays with the arguments that were passed to the "enqueue"
+ * method (the oldest being at the end of the vector). */
+ protected var _queue:Vector.;
+
+ /** The list of all currently active touches. */
+ protected var _currentTouches:Vector.;
+
+ /** Helper objects. */
+ private static var sUpdatedTouches:Vector. = new [];
+ private static var sHoveringTouchData:Vector.