PageRenderTime 142ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/starling/core/Starling.as

https://bitbucket.org/tshubbard/zfstarlingtutorial
ActionScript | 862 lines | 524 code | 122 blank | 216 comment | 94 complexity | be160d00e7e0df77697f0db6df95c01e MD5 | raw file
  1. // =================================================================================================
  2. //
  3. // Starling Framework
  4. // Copyright 2012 Gamua OG. All Rights Reserved.
  5. //
  6. // This program is free software. You can redistribute and/or modify it
  7. // in accordance with the terms of the accompanying license agreement.
  8. //
  9. // =================================================================================================
  10. package starling.core
  11. {
  12. import flash.display.Sprite;
  13. import flash.display.Stage3D;
  14. import flash.display.StageAlign;
  15. import flash.display.StageScaleMode;
  16. import flash.display3D.Context3D;
  17. import flash.display3D.Context3DCompareMode;
  18. import flash.display3D.Context3DTriangleFace;
  19. import flash.display3D.Program3D;
  20. import flash.errors.IllegalOperationError;
  21. import flash.events.ErrorEvent;
  22. import flash.events.Event;
  23. import flash.events.KeyboardEvent;
  24. import flash.events.MouseEvent;
  25. import flash.events.TouchEvent;
  26. import flash.geom.Rectangle;
  27. import flash.text.TextField;
  28. import flash.text.TextFieldAutoSize;
  29. import flash.text.TextFormat;
  30. import flash.text.TextFormatAlign;
  31. import flash.ui.Mouse;
  32. import flash.ui.Multitouch;
  33. import flash.ui.MultitouchInputMode;
  34. import flash.utils.ByteArray;
  35. import flash.utils.Dictionary;
  36. import flash.utils.getTimer;
  37. import flash.utils.setTimeout;
  38. import starling.animation.Juggler;
  39. import starling.display.DisplayObject;
  40. import starling.display.Stage;
  41. import starling.events.EventDispatcher;
  42. import starling.events.ResizeEvent;
  43. import starling.events.TouchPhase;
  44. import starling.utils.HAlign;
  45. import starling.utils.VAlign;
  46. /** Dispatched when a new render context is created. */
  47. [Event(name="context3DCreate", type="starling.events.Event")]
  48. /** Dispatched when the root class has been created. */
  49. [Event(name="rootCreated", type="starling.events.Event")]
  50. /** The Starling class represents the core of the Starling framework.
  51. *
  52. * <p>The Starling framework makes it possible to create 2D applications and games that make
  53. * use of the Stage3D architecture introduced in Flash Player 11. It implements a display tree
  54. * system that is very similar to that of conventional Flash, while leveraging modern GPUs
  55. * to speed up rendering.</p>
  56. *
  57. * <p>The Starling class represents the link between the conventional Flash display tree and
  58. * the Starling display tree. To create a Starling-powered application, you have to create
  59. * an instance of the Starling class:</p>
  60. *
  61. * <pre>var starling:Starling = new Starling(Game, stage);</pre>
  62. *
  63. * <p>The first parameter has to be a Starling display object class, e.g. a subclass of
  64. * <code>starling.display.Sprite</code>. In the sample above, the class "Game" is the
  65. * application root. An instance of "Game" will be created as soon as Starling is initialized.
  66. * The second parameter is the conventional (Flash) stage object. Per default, Starling will
  67. * display its contents directly below the stage.</p>
  68. *
  69. * <p>It is recommended to store the Starling instance as a member variable, to make sure
  70. * that the Garbage Collector does not destroy it. After creating the Starling object, you
  71. * have to start it up like this:</p>
  72. *
  73. * <pre>starling.start();</pre>
  74. *
  75. * <p>It will now render the contents of the "Game" class in the frame rate that is set up for
  76. * the application (as defined in the Flash stage).</p>
  77. *
  78. * <strong>Accessing the Starling object</strong>
  79. *
  80. * <p>From within your application, you can access the current Starling object anytime
  81. * through the static method <code>Starling.current</code>. It will return the active Starling
  82. * instance (most applications will only have one Starling object, anyway).</p>
  83. *
  84. * <strong>Viewport</strong>
  85. *
  86. * <p>The area the Starling content is rendered into is, per default, the complete size of the
  87. * stage. You can, however, use the "viewPort" property to change it. This can be useful
  88. * when you want to render only into a part of the screen, or if the player size changes. For
  89. * the latter, you can listen to the RESIZE-event dispatched by the Starling
  90. * stage.</p>
  91. *
  92. * <strong>Native overlay</strong>
  93. *
  94. * <p>Sometimes you will want to display native Flash content on top of Starling. That's what the
  95. * <code>nativeOverlay</code> property is for. It returns a Flash Sprite lying directly
  96. * on top of the Starling content. You can add conventional Flash objects to that overlay.</p>
  97. *
  98. * <p>Beware, though, that conventional Flash content on top of 3D content can lead to
  99. * performance penalties on some (mobile) platforms. For that reason, always remove all child
  100. * objects from the overlay when you don't need them any longer. Starling will remove the
  101. * overlay from the display list when it's empty.</p>
  102. *
  103. * <strong>Multitouch</strong>
  104. *
  105. * <p>Starling supports multitouch input on devices that provide it. During development,
  106. * where most of us are working with a conventional mouse and keyboard, Starling can simulate
  107. * multitouch events with the help of the "Shift" and "Ctrl" (Mac: "Cmd") keys. Activate
  108. * this feature by enabling the <code>simulateMultitouch</code> property.</p>
  109. *
  110. * <strong>Handling a lost render context</strong>
  111. *
  112. * <p>On some operating systems and under certain conditions (e.g. returning from system
  113. * sleep), Starling's stage3D render context may be lost. Starling can recover from a lost
  114. * context if the class property "handleLostContext" is set to "true". Keep in mind, however,
  115. * that this comes at the price of increased memory consumption; Starling will cache textures
  116. * in RAM to be able to restore them when the context is lost.</p>
  117. *
  118. * <p>In case you want to react to a context loss, Starling dispatches an event with
  119. * the type "Event.CONTEXT3D_CREATE" when the context is restored. You can recreate any
  120. * invalid resources in a corresponding event listener.</p>
  121. *
  122. * <strong>Sharing a 3D Context</strong>
  123. *
  124. * <p>Per default, Starling handles the Stage3D context independently. If you want to combine
  125. * Starling with another Stage3D engine, however, this may not be what you want. In this case,
  126. * you can make use of the <code>shareContext</code> property:</p>
  127. *
  128. * <ol>
  129. * <li>Manually create and configure a context3D object that both frameworks can work with
  130. * (through <code>stage3D.requestContext3D</code> and
  131. * <code>context.configureBackBuffer</code>).</li>
  132. * <li>Initialize Starling with the stage3D instance that contains that configured context.
  133. * This will automatically enable <code>shareContext</code>.</li>
  134. * <li>Call <code>start()</code> on your Starling instance (as usual). This will make
  135. * Starling queue input events (keyboard/mouse/touch).</li>
  136. * <li>Create a game loop (e.g. using the native <code>ENTER_FRAME</code> event) and let it
  137. * call Starling's <code>nextFrame</code> as well as the equivalent method of the other
  138. * Stage3D engine. Surround those calls with <code>context.clear()</code> and
  139. * <code>context.present()</code>.</li>
  140. * </ol>
  141. *
  142. * <p>The Starling wiki contains a <a href="http://goo.gl/BsXzw">tutorial</a> with more
  143. * information about this topic.</p>
  144. *
  145. */
  146. public class Starling extends EventDispatcher
  147. {
  148. /** The version of the Starling framework. */
  149. public static const VERSION:String = "1.3";
  150. /** The key for the shader programs stored in 'contextData' */
  151. private static const PROGRAM_DATA_NAME:String = "Starling.programs";
  152. // members
  153. private var mStage3D:Stage3D;
  154. private var mStage:Stage; // starling.display.stage!
  155. private var mRootClass:Class;
  156. private var mRoot:DisplayObject;
  157. private var mJuggler:Juggler;
  158. private var mStarted:Boolean;
  159. private var mSupport:RenderSupport;
  160. private var mTouchProcessor:TouchProcessor;
  161. private var mAntiAliasing:int;
  162. private var mSimulateMultitouch:Boolean;
  163. private var mEnableErrorChecking:Boolean;
  164. private var mLastFrameTimestamp:Number;
  165. private var mLeftMouseDown:Boolean;
  166. private var mStatsDisplay:StatsDisplay;
  167. private var mShareContext:Boolean;
  168. private var mProfile:String;
  169. private var mContext:Context3D;
  170. private var mViewPort:Rectangle;
  171. private var mPreviousViewPort:Rectangle;
  172. private var mClippedViewPort:Rectangle;
  173. private var mNativeStage:flash.display.Stage;
  174. private var mNativeOverlay:flash.display.Sprite;
  175. private static var sCurrent:Starling;
  176. private static var sHandleLostContext:Boolean;
  177. private static var sContextData:Dictionary = new Dictionary(true);
  178. // construction
  179. /** Creates a new Starling instance.
  180. * @param rootClass A subclass of a Starling display object. It will be created as soon as
  181. * initialization is finished and will become the first child of the
  182. * Starling stage.
  183. * @param stage The Flash (2D) stage.
  184. * @param viewPort A rectangle describing the area into which the content will be
  185. * rendered. @default stage size
  186. * @param stage3D The Stage3D object into which the content will be rendered. If it
  187. * already contains a context, <code>sharedContext</code> will be set
  188. * to <code>true</code>. @default the first available Stage3D.
  189. * @param renderMode Use this parameter to force "software" rendering.
  190. * @param profile The Context3DProfile that should be requested.
  191. */
  192. public function Starling(rootClass:Class, stage:flash.display.Stage,
  193. viewPort:Rectangle=null, stage3D:Stage3D=null,
  194. renderMode:String="auto", profile:String="baselineConstrained")
  195. {
  196. if (stage == null) throw new ArgumentError("Stage must not be null");
  197. if (rootClass == null) throw new ArgumentError("Root class must not be null");
  198. if (viewPort == null) viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
  199. if (stage3D == null) stage3D = stage.stage3Ds[0];
  200. makeCurrent();
  201. mRootClass = rootClass;
  202. mViewPort = viewPort;
  203. mPreviousViewPort = new Rectangle();
  204. mStage3D = stage3D;
  205. mStage = new Stage(viewPort.width, viewPort.height, stage.color);
  206. mNativeOverlay = new Sprite();
  207. mNativeStage = stage;
  208. mNativeStage.addChild(mNativeOverlay);
  209. mTouchProcessor = new TouchProcessor(mStage);
  210. mJuggler = new Juggler();
  211. mAntiAliasing = 0;
  212. mSimulateMultitouch = false;
  213. mEnableErrorChecking = false;
  214. mProfile = profile;
  215. mLastFrameTimestamp = getTimer() / 1000.0;
  216. mSupport = new RenderSupport();
  217. // for context data, we actually reference by stage3D, since it survives a context loss
  218. sContextData[stage3D] = new Dictionary();
  219. sContextData[stage3D][PROGRAM_DATA_NAME] = new Dictionary();
  220. // all other modes are problematic in Starling, so we force those here
  221. stage.scaleMode = StageScaleMode.NO_SCALE;
  222. stage.align = StageAlign.TOP_LEFT;
  223. // register touch/mouse event handlers
  224. for each (var touchEventType:String in touchEventTypes)
  225. stage.addEventListener(touchEventType, onTouch, false, 0, true);
  226. // register other event handlers
  227. stage.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
  228. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey, false, 0, true);
  229. stage.addEventListener(KeyboardEvent.KEY_UP, onKey, false, 0, true);
  230. stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
  231. stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave, false, 0, true);
  232. mStage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 10, true);
  233. mStage3D.addEventListener(ErrorEvent.ERROR, onStage3DError, false, 10, true);
  234. if (mStage3D.context3D && mStage3D.context3D.driverInfo != "Disposed")
  235. {
  236. mShareContext = true;
  237. setTimeout(initialize, 1); // we don't call it right away, because Starling should
  238. // behave the same way with or without a shared context
  239. }
  240. else
  241. {
  242. mShareContext = false;
  243. try
  244. {
  245. // "Context3DProfile" is only available starting with Flash Player 11.4/AIR 3.4.
  246. // to stay compatible with older versions, we check if the parameter is available.
  247. var requestContext3D:Function = mStage3D.requestContext3D;
  248. if (requestContext3D.length == 1) requestContext3D(renderMode);
  249. else requestContext3D(renderMode, profile);
  250. }
  251. catch (e:Error)
  252. {
  253. showFatalError("Context3D error: " + e.message);
  254. }
  255. }
  256. }
  257. /** Disposes all children of the stage and the render context; removes all registered
  258. * event listeners. */
  259. public function dispose():void
  260. {
  261. stop();
  262. mNativeStage.removeEventListener(Event.ENTER_FRAME, onEnterFrame, false);
  263. mNativeStage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey, false);
  264. mNativeStage.removeEventListener(KeyboardEvent.KEY_UP, onKey, false);
  265. mNativeStage.removeEventListener(Event.RESIZE, onResize, false);
  266. mNativeStage.removeEventListener(Event.MOUSE_LEAVE, onMouseLeave, false);
  267. mNativeStage.removeChild(mNativeOverlay);
  268. mStage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false);
  269. mStage3D.removeEventListener(ErrorEvent.ERROR, onStage3DError, false);
  270. for each (var touchEventType:String in touchEventTypes)
  271. mNativeStage.removeEventListener(touchEventType, onTouch, false);
  272. if (mStage) mStage.dispose();
  273. if (mSupport) mSupport.dispose();
  274. if (mTouchProcessor) mTouchProcessor.dispose();
  275. if (mContext && !mShareContext) mContext.dispose();
  276. if (sCurrent == this) sCurrent = null;
  277. }
  278. // functions
  279. private function initialize():void
  280. {
  281. makeCurrent();
  282. initializeGraphicsAPI();
  283. initializeRoot();
  284. mTouchProcessor.simulateMultitouch = mSimulateMultitouch;
  285. mLastFrameTimestamp = getTimer() / 1000.0;
  286. }
  287. private function initializeGraphicsAPI():void
  288. {
  289. mContext = mStage3D.context3D;
  290. mContext.enableErrorChecking = mEnableErrorChecking;
  291. contextData[PROGRAM_DATA_NAME] = new Dictionary();
  292. updateViewPort(true);
  293. trace("[Starling] Initialization complete.");
  294. trace("[Starling] Display Driver:", mContext.driverInfo);
  295. dispatchEventWith(starling.events.Event.CONTEXT3D_CREATE, false, mContext);
  296. }
  297. private function initializeRoot():void
  298. {
  299. if (mRoot == null)
  300. {
  301. mRoot = new mRootClass() as DisplayObject;
  302. if (mRoot == null) throw new Error("Invalid root class: " + mRootClass);
  303. mStage.addChildAt(mRoot, 0);
  304. dispatchEventWith(starling.events.Event.ROOT_CREATED, false, mRoot);
  305. }
  306. }
  307. /** Calls <code>advanceTime()</code> (with the time that has passed since the last frame)
  308. * and <code>render()</code>. */
  309. public function nextFrame():void
  310. {
  311. var now:Number = getTimer() / 1000.0;
  312. var passedTime:Number = now - mLastFrameTimestamp;
  313. mLastFrameTimestamp = now;
  314. advanceTime(passedTime);
  315. render();
  316. }
  317. /** Dispatches ENTER_FRAME events on the display list, advances the Juggler
  318. * and processes touches. */
  319. public function advanceTime(passedTime:Number):void
  320. {
  321. makeCurrent();
  322. mTouchProcessor.advanceTime(passedTime);
  323. mStage.advanceTime(passedTime);
  324. mJuggler.advanceTime(passedTime);
  325. }
  326. /** Renders the complete display list. Before rendering, the context is cleared; afterwards,
  327. * it is presented. This can be avoided by enabling <code>shareContext</code>.*/
  328. public function render():void
  329. {
  330. if (!contextValid)
  331. return;
  332. makeCurrent();
  333. updateViewPort();
  334. updateNativeOverlay();
  335. mSupport.nextFrame();
  336. if (!mShareContext)
  337. RenderSupport.clear(mStage.color, 1.0);
  338. var scaleX:Number = mViewPort.width / mStage.stageWidth;
  339. var scaleY:Number = mViewPort.height / mStage.stageHeight;
  340. mContext.setDepthTest(false, Context3DCompareMode.ALWAYS);
  341. mContext.setCulling(Context3DTriangleFace.NONE);
  342. mSupport.renderTarget = null; // back buffer
  343. mSupport.setOrthographicProjection(
  344. mViewPort.x < 0 ? -mViewPort.x / scaleX : 0.0,
  345. mViewPort.y < 0 ? -mViewPort.y / scaleY : 0.0,
  346. mClippedViewPort.width / scaleX,
  347. mClippedViewPort.height / scaleY);
  348. mStage.render(mSupport, 1.0);
  349. mSupport.finishQuadBatch();
  350. if (mStatsDisplay)
  351. mStatsDisplay.drawCount = mSupport.drawCount;
  352. if (!mShareContext)
  353. mContext.present();
  354. }
  355. private function updateViewPort(updateAliasing:Boolean=false):void
  356. {
  357. // the last set viewport is stored in a variable; that way, people can modify the
  358. // viewPort directly (without a copy) and we still know if it has changed.
  359. if (updateAliasing || mPreviousViewPort.width != mViewPort.width ||
  360. mPreviousViewPort.height != mViewPort.height ||
  361. mPreviousViewPort.x != mViewPort.x || mPreviousViewPort.y != mViewPort.y)
  362. {
  363. mPreviousViewPort.setTo(mViewPort.x, mViewPort.y, mViewPort.width, mViewPort.height);
  364. // Constrained mode requires that the viewport is within the native stage bounds;
  365. // thus, we use a clipped viewport when configuring the back buffer. (In baseline
  366. // mode, that's not necessary, but it does not hurt either.)
  367. mClippedViewPort = mViewPort.intersection(
  368. new Rectangle(0, 0, mNativeStage.stageWidth, mNativeStage.stageHeight));
  369. if (!mShareContext)
  370. {
  371. // setting x and y might move the context to invalid bounds (since changing
  372. // the size happens in a separate operation) -- so we have no choice but to
  373. // set the backbuffer to a very small size first, to be on the safe side.
  374. if (mProfile == "baselineConstrained")
  375. mSupport.configureBackBuffer(32, 32, mAntiAliasing, false);
  376. mStage3D.x = mClippedViewPort.x;
  377. mStage3D.y = mClippedViewPort.y;
  378. mSupport.configureBackBuffer(
  379. mClippedViewPort.width, mClippedViewPort.height, mAntiAliasing, false);
  380. }
  381. else
  382. {
  383. mSupport.backBufferWidth = mClippedViewPort.width;
  384. mSupport.backBufferHeight = mClippedViewPort.height;
  385. }
  386. }
  387. }
  388. private function updateNativeOverlay():void
  389. {
  390. mNativeOverlay.x = mViewPort.x;
  391. mNativeOverlay.y = mViewPort.y;
  392. mNativeOverlay.scaleX = mViewPort.width / mStage.stageWidth;
  393. mNativeOverlay.scaleY = mViewPort.height / mStage.stageHeight;
  394. }
  395. private function showFatalError(message:String):void
  396. {
  397. var textField:TextField = new TextField();
  398. var textFormat:TextFormat = new TextFormat("Verdana", 12, 0xFFFFFF);
  399. textFormat.align = TextFormatAlign.CENTER;
  400. textField.defaultTextFormat = textFormat;
  401. textField.wordWrap = true;
  402. textField.width = mStage.stageWidth * 0.75;
  403. textField.autoSize = TextFieldAutoSize.CENTER;
  404. textField.text = message;
  405. textField.x = (mStage.stageWidth - textField.width) / 2;
  406. textField.y = (mStage.stageHeight - textField.height) / 2;
  407. textField.background = true;
  408. textField.backgroundColor = 0x440000;
  409. nativeOverlay.addChild(textField);
  410. }
  411. /** Make this Starling instance the <code>current</code> one. */
  412. public function makeCurrent():void
  413. {
  414. sCurrent = this;
  415. }
  416. /** As soon as Starling is started, it will queue input events (keyboard/mouse/touch);
  417. * furthermore, the method <code>nextFrame</code> will be called once per Flash Player
  418. * frame. (Except when <code>shareContext</code> is enabled: in that case, you have to
  419. * call that method manually.) */
  420. public function start():void
  421. {
  422. mStarted = true;
  423. mLastFrameTimestamp = getTimer() / 1000.0;
  424. }
  425. /** Stops all logic processing and freezes the game in its current state. The content
  426. * is still being rendered once per frame, though, because otherwise the conventional
  427. * display list would no longer be updated. */
  428. public function stop():void
  429. {
  430. mStarted = false;
  431. }
  432. // event handlers
  433. private function onStage3DError(event:ErrorEvent):void
  434. {
  435. if (event.errorID == 3702)
  436. showFatalError("This application is not correctly embedded (wrong wmode value)");
  437. else
  438. showFatalError("Stage3D error: " + event.text);
  439. }
  440. private function onContextCreated(event:Event):void
  441. {
  442. if (!Starling.handleLostContext && mContext)
  443. {
  444. stop();
  445. event.stopImmediatePropagation();
  446. showFatalError("Fatal error: The application lost the device context!");
  447. trace("[Starling] The device context was lost. " +
  448. "Enable 'Starling.handleLostContext' to avoid this error.");
  449. }
  450. else
  451. {
  452. initialize();
  453. }
  454. }
  455. private function onEnterFrame(event:Event):void
  456. {
  457. // On mobile, the native display list is only updated on stage3D draw calls.
  458. // Thus, we render even when Starling is paused.
  459. if (!mShareContext)
  460. {
  461. if (mStarted) nextFrame();
  462. else render();
  463. }
  464. }
  465. private function onKey(event:KeyboardEvent):void
  466. {
  467. if (!mStarted) return;
  468. makeCurrent();
  469. mStage.dispatchEvent(new starling.events.KeyboardEvent(
  470. event.type, event.charCode, event.keyCode, event.keyLocation,
  471. event.ctrlKey, event.altKey, event.shiftKey));
  472. }
  473. private function onResize(event:Event):void
  474. {
  475. var stage:flash.display.Stage = event.target as flash.display.Stage;
  476. mStage.dispatchEvent(new ResizeEvent(Event.RESIZE, stage.stageWidth, stage.stageHeight));
  477. }
  478. private function onMouseLeave(event:Event):void
  479. {
  480. mTouchProcessor.enqueueMouseLeftStage();
  481. }
  482. private function onTouch(event:Event):void
  483. {
  484. if (!mStarted) return;
  485. var globalX:Number;
  486. var globalY:Number;
  487. var touchID:int;
  488. var phase:String;
  489. var pressure:Number = 1.0;
  490. var width:Number = 1.0;
  491. var height:Number = 1.0;
  492. // figure out general touch properties
  493. if (event is MouseEvent)
  494. {
  495. var mouseEvent:MouseEvent = event as MouseEvent;
  496. globalX = mouseEvent.stageX;
  497. globalY = mouseEvent.stageY;
  498. touchID = 0;
  499. // MouseEvent.buttonDown returns true for both left and right button (AIR supports
  500. // the right mouse button). We only want to react on the left button for now,
  501. // so we have to save the state for the left button manually.
  502. if (event.type == MouseEvent.MOUSE_DOWN) mLeftMouseDown = true;
  503. else if (event.type == MouseEvent.MOUSE_UP) mLeftMouseDown = false;
  504. }
  505. else
  506. {
  507. var touchEvent:TouchEvent = event as TouchEvent;
  508. globalX = touchEvent.stageX;
  509. globalY = touchEvent.stageY;
  510. touchID = touchEvent.touchPointID;
  511. pressure = touchEvent.pressure;
  512. width = touchEvent.sizeX;
  513. height = touchEvent.sizeY;
  514. }
  515. // figure out touch phase
  516. switch (event.type)
  517. {
  518. case TouchEvent.TOUCH_BEGIN: phase = TouchPhase.BEGAN; break;
  519. case TouchEvent.TOUCH_MOVE: phase = TouchPhase.MOVED; break;
  520. case TouchEvent.TOUCH_END: phase = TouchPhase.ENDED; break;
  521. case MouseEvent.MOUSE_DOWN: phase = TouchPhase.BEGAN; break;
  522. case MouseEvent.MOUSE_UP: phase = TouchPhase.ENDED; break;
  523. case MouseEvent.MOUSE_MOVE:
  524. phase = (mLeftMouseDown ? TouchPhase.MOVED : TouchPhase.HOVER); break;
  525. }
  526. // move position into viewport bounds
  527. globalX = mStage.stageWidth * (globalX - mViewPort.x) / mViewPort.width;
  528. globalY = mStage.stageHeight * (globalY - mViewPort.y) / mViewPort.height;
  529. // enqueue touch in touch processor
  530. mTouchProcessor.enqueue(touchID, phase, globalX, globalY, pressure, width, height);
  531. }
  532. private function get touchEventTypes():Array
  533. {
  534. return Mouse.supportsCursor || !multitouchEnabled ?
  535. [ MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_MOVE, MouseEvent.MOUSE_UP ] :
  536. [ TouchEvent.TOUCH_BEGIN, TouchEvent.TOUCH_MOVE, TouchEvent.TOUCH_END ];
  537. }
  538. // program management
  539. /** Registers a vertex- and fragment-program under a certain name. If the name was already
  540. * used, the previous program is overwritten. */
  541. public function registerProgram(name:String, vertexProgram:ByteArray, fragmentProgram:ByteArray):void
  542. {
  543. deleteProgram(name);
  544. var program:Program3D = mContext.createProgram();
  545. program.upload(vertexProgram, fragmentProgram);
  546. programs[name] = program;
  547. }
  548. /** Deletes the vertex- and fragment-programs of a certain name. */
  549. public function deleteProgram(name:String):void
  550. {
  551. var program:Program3D = getProgram(name);
  552. if (program)
  553. {
  554. program.dispose();
  555. delete programs[name];
  556. }
  557. }
  558. /** Returns the vertex- and fragment-programs registered under a certain name. */
  559. public function getProgram(name:String):Program3D
  560. {
  561. return programs[name] as Program3D;
  562. }
  563. /** Indicates if a set of vertex- and fragment-programs is registered under a certain name. */
  564. public function hasProgram(name:String):Boolean
  565. {
  566. return name in programs;
  567. }
  568. private function get programs():Dictionary { return contextData[PROGRAM_DATA_NAME]; }
  569. // properties
  570. /** Indicates if a context is available and non-disposed. */
  571. private function get contextValid():Boolean
  572. {
  573. return (mContext && mContext.driverInfo != "Disposed");
  574. }
  575. /** Indicates if this Starling instance is started. */
  576. public function get isStarted():Boolean { return mStarted; }
  577. /** The default juggler of this instance. Will be advanced once per frame. */
  578. public function get juggler():Juggler { return mJuggler; }
  579. /** The render context of this instance. */
  580. public function get context():Context3D { return mContext; }
  581. /** A dictionary that can be used to save custom data related to the current context.
  582. * If you need to share data that is bound to a specific stage3D instance
  583. * (e.g. textures), use this dictionary instead of creating a static class variable.
  584. * The Dictionary is actually bound to the stage3D instance, thus it survives a
  585. * context loss. */
  586. public function get contextData():Dictionary
  587. {
  588. return sContextData[mStage3D] as Dictionary;
  589. }
  590. /** Indicates if multitouch simulation with "Shift" and "Ctrl"/"Cmd"-keys is enabled.
  591. * @default false */
  592. public function get simulateMultitouch():Boolean { return mSimulateMultitouch; }
  593. public function set simulateMultitouch(value:Boolean):void
  594. {
  595. mSimulateMultitouch = value;
  596. if (mContext) mTouchProcessor.simulateMultitouch = value;
  597. }
  598. /** Indicates if Stage3D render methods will report errors. Activate only when needed,
  599. * as this has a negative impact on performance. @default false */
  600. public function get enableErrorChecking():Boolean { return mEnableErrorChecking; }
  601. public function set enableErrorChecking(value:Boolean):void
  602. {
  603. mEnableErrorChecking = value;
  604. if (mContext) mContext.enableErrorChecking = value;
  605. }
  606. /** The antialiasing level. 0 - no antialasing, 16 - maximum antialiasing. @default 0 */
  607. public function get antiAliasing():int { return mAntiAliasing; }
  608. public function set antiAliasing(value:int):void
  609. {
  610. if (mAntiAliasing != value)
  611. {
  612. mAntiAliasing = value;
  613. if (contextValid) updateViewPort(true);
  614. }
  615. }
  616. /** The viewport into which Starling contents will be rendered. */
  617. public function get viewPort():Rectangle { return mViewPort; }
  618. public function set viewPort(value:Rectangle):void { mViewPort = value.clone(); }
  619. /** The ratio between viewPort width and stage width. Useful for choosing a different
  620. * set of textures depending on the display resolution. */
  621. public function get contentScaleFactor():Number
  622. {
  623. return mViewPort.width / mStage.stageWidth;
  624. }
  625. /** A Flash Sprite placed directly on top of the Starling content. Use it to display native
  626. * Flash components. */
  627. public function get nativeOverlay():Sprite { return mNativeOverlay; }
  628. /** Indicates if a small statistics box (with FPS, memory usage and draw count) is displayed. */
  629. public function get showStats():Boolean { return mStatsDisplay && mStatsDisplay.parent; }
  630. public function set showStats(value:Boolean):void
  631. {
  632. if (value == showStats) return;
  633. if (value)
  634. {
  635. if (mStatsDisplay) mStage.addChild(mStatsDisplay);
  636. else showStatsAt();
  637. }
  638. else mStatsDisplay.removeFromParent();
  639. }
  640. /** Displays the statistics box at a certain position. */
  641. public function showStatsAt(hAlign:String="left", vAlign:String="top", scale:Number=1):void
  642. {
  643. if (mContext == null)
  644. {
  645. // Starling is not yet ready - we postpone this until it's initialized.
  646. addEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
  647. }
  648. else
  649. {
  650. if (mStatsDisplay == null)
  651. {
  652. mStatsDisplay = new StatsDisplay();
  653. mStatsDisplay.touchable = false;
  654. mStage.addChild(mStatsDisplay);
  655. }
  656. var stageWidth:int = mStage.stageWidth;
  657. var stageHeight:int = mStage.stageHeight;
  658. mStatsDisplay.scaleX = mStatsDisplay.scaleY = scale;
  659. if (hAlign == HAlign.LEFT) mStatsDisplay.x = 0;
  660. else if (hAlign == HAlign.RIGHT) mStatsDisplay.x = stageWidth - mStatsDisplay.width;
  661. else mStatsDisplay.x = int((stageWidth - mStatsDisplay.width) / 2);
  662. if (vAlign == VAlign.TOP) mStatsDisplay.y = 0;
  663. else if (vAlign == VAlign.BOTTOM) mStatsDisplay.y = stageHeight - mStatsDisplay.height;
  664. else mStatsDisplay.y = int((stageHeight - mStatsDisplay.height) / 2);
  665. }
  666. function onRootCreated():void
  667. {
  668. showStatsAt(hAlign, vAlign, scale);
  669. removeEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
  670. }
  671. }
  672. /** The Starling stage object, which is the root of the display tree that is rendered. */
  673. public function get stage():Stage
  674. {
  675. return mStage;
  676. }
  677. /** The Flash Stage3D object Starling renders into. */
  678. public function get stage3D():Stage3D
  679. {
  680. return mStage3D;
  681. }
  682. /** The Flash (2D) stage object Starling renders beneath. */
  683. public function get nativeStage():flash.display.Stage
  684. {
  685. return mNativeStage;
  686. }
  687. /** The instance of the root class provided in the constructor. Available as soon as
  688. * the event 'ROOT_CREATED' has been dispatched. */
  689. public function get root():DisplayObject
  690. {
  691. return mRoot;
  692. }
  693. /** Indicates if the Context3D render calls are managed externally to Starling,
  694. * to allow other frameworks to share the Stage3D instance. @default false */
  695. public function get shareContext() : Boolean { return mShareContext; }
  696. public function set shareContext(value : Boolean) : void { mShareContext = value; }
  697. /** The Context3D profile as requested in the constructor. Beware that if you are
  698. * using a shared context, this might not be accurate. */
  699. public function get profile():String { return mProfile; }
  700. // static properties
  701. /** The currently active Starling instance. */
  702. public static function get current():Starling { return sCurrent; }
  703. /** The render context of the currently active Starling instance. */
  704. public static function get context():Context3D { return sCurrent ? sCurrent.context : null; }
  705. /** The default juggler of the currently active Starling instance. */
  706. public static function get juggler():Juggler { return sCurrent ? sCurrent.juggler : null; }
  707. /** The contentScaleFactor of the currently active Starling instance. */
  708. public static function get contentScaleFactor():Number
  709. {
  710. return sCurrent ? sCurrent.contentScaleFactor : 1.0;
  711. }
  712. /** Indicates if multitouch input should be supported. */
  713. public static function get multitouchEnabled():Boolean
  714. {
  715. return Multitouch.inputMode == MultitouchInputMode.TOUCH_POINT;
  716. }
  717. public static function set multitouchEnabled(value:Boolean):void
  718. {
  719. if (sCurrent) throw new IllegalOperationError(
  720. "'multitouchEnabled' must be set before Starling instance is created");
  721. else
  722. Multitouch.inputMode = value ? MultitouchInputMode.TOUCH_POINT :
  723. MultitouchInputMode.NONE;
  724. }
  725. /** Indicates if Starling should automatically recover from a lost device context.
  726. * On some systems, an upcoming screensaver or entering sleep mode may
  727. * invalidate the render context. This setting indicates if Starling should recover from
  728. * such incidents. Beware that this has a huge impact on memory consumption!
  729. * It is recommended to enable this setting on Android and Windows, but to deactivate it
  730. * on iOS and Mac OS X. @default false */
  731. public static function get handleLostContext():Boolean { return sHandleLostContext; }
  732. public static function set handleLostContext(value:Boolean):void
  733. {
  734. if (sCurrent) throw new IllegalOperationError(
  735. "'handleLostContext' must be set before Starling instance is created");
  736. else
  737. sHandleLostContext = value;
  738. }
  739. }
  740. }