Advertisement
Guest User

Starling.as

a guest
Mar 23rd, 2020
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 39.88 KB | None | 0 0
  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.  
  11. package starling.core {
  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.system.Capabilities;
  28. import flash.text.TextField;
  29. import flash.text.TextFieldAutoSize;
  30. import flash.text.TextFormat;
  31. import flash.text.TextFormatAlign;
  32. import flash.ui.Mouse;
  33. import flash.ui.Multitouch;
  34. import flash.ui.MultitouchInputMode;
  35. import flash.utils.ByteArray;
  36. import flash.utils.Dictionary;
  37. import flash.utils.getTimer;
  38. import flash.utils.setTimeout;
  39.  
  40. import starling.animation.Juggler;
  41. import starling.display.DisplayObject;
  42. import starling.display.Stage;
  43. import starling.events.EventDispatcher;
  44. import starling.events.ResizeEvent;
  45. import starling.events.TouchPhase;
  46. import starling.events.TouchProcessor;
  47. import starling.utils.HAlign;
  48. import starling.utils.VAlign;
  49.  
  50. /** Dispatched when a new render context is created. */
  51. [Event(name="context3DCreate", type="starling.events.Event")]
  52.  
  53. /** Dispatched when the root class has been created. */
  54. [Event(name="rootCreated", type="starling.events.Event")]
  55.  
  56. /** The Starling class represents the core of the Starling framework.
  57. *
  58. * <p>The Starling framework makes it possible to create 2D applications and games that make
  59. * use of the Stage3D architecture introduced in Flash Player 11. It implements a display tree
  60. * system that is very similar to that of conventional Flash, while leveraging modern GPUs
  61. * to speed up rendering.</p>
  62. *
  63. * <p>The Starling class represents the link between the conventional Flash display tree and
  64. * the Starling display tree. To create a Starling-powered application, you have to create
  65. * an instance of the Starling class:</p>
  66. *
  67. * <pre>var starling:Starling = new Starling(Game, stage);</pre>
  68. *
  69. * <p>The first parameter has to be a Starling display object class, e.g. a subclass of
  70. * <code>starling.display.Sprite</code>. In the sample above, the class "Game" is the
  71. * application root. An instance of "Game" will be created as soon as Starling is initialized.
  72. * The second parameter is the conventional (Flash) stage object. Per default, Starling will
  73. * display its contents directly below the stage.</p>
  74. *
  75. * <p>It is recommended to store the Starling instance as a member variable, to make sure
  76. * that the Garbage Collector does not destroy it. After creating the Starling object, you
  77. * have to start it up like this:</p>
  78. *
  79. * <pre>starling.start();</pre>
  80. *
  81. * <p>It will now render the contents of the "Game" class in the frame rate that is set up for
  82. * the application (as defined in the Flash stage).</p>
  83. *
  84. * <strong>Accessing the Starling object</strong>
  85. *
  86. * <p>From within your application, you can access the current Starling object anytime
  87. * through the static method <code>Starling.current</code>. It will return the active Starling
  88. * instance (most applications will only have one Starling object, anyway).</p>
  89. *
  90. * <strong>Viewport</strong>
  91. *
  92. * <p>The area the Starling content is rendered into is, per default, the complete size of the
  93. * stage. You can, however, use the "viewPort" property to change it. This can be useful
  94. * when you want to render only into a part of the screen, or if the player size changes. For
  95. * the latter, you can listen to the RESIZE-event dispatched by the Starling
  96. * stage.</p>
  97. *
  98. * <strong>Native overlay</strong>
  99. *
  100. * <p>Sometimes you will want to display native Flash content on top of Starling. That's what the
  101. * <code>nativeOverlay</code> property is for. It returns a Flash Sprite lying directly
  102. * on top of the Starling content. You can add conventional Flash objects to that overlay.</p>
  103. *
  104. * <p>Beware, though, that conventional Flash content on top of 3D content can lead to
  105. * performance penalties on some (mobile) platforms. For that reason, always remove all child
  106. * objects from the overlay when you don't need them any longer. Starling will remove the
  107. * overlay from the display list when it's empty.</p>
  108. *
  109. * <strong>Multitouch</strong>
  110. *
  111. * <p>Starling supports multitouch input on devices that provide it. During development,
  112. * where most of us are working with a conventional mouse and keyboard, Starling can simulate
  113. * multitouch events with the help of the "Shift" and "Ctrl" (Mac: "Cmd") keys. Activate
  114. * this feature by enabling the <code>simulateMultitouch</code> property.</p>
  115. *
  116. * <strong>Handling a lost render context</strong>
  117. *
  118. * <p>On some operating systems and under certain conditions (e.g. returning from system
  119. * sleep), Starling's stage3D render context may be lost. Starling can recover from a lost
  120. * context if the class property "handleLostContext" is set to "true". Keep in mind, however,
  121. * that this comes at the price of increased memory consumption; Starling will cache textures
  122. * in RAM to be able to restore them when the context is lost.</p>
  123. *
  124. * <p>In case you want to react to a context loss, Starling dispatches an event with
  125. * the type "Event.CONTEXT3D_CREATE" when the context is restored. You can recreate any
  126. * invalid resources in a corresponding event listener.</p>
  127. *
  128. * <strong>Sharing a 3D Context</strong>
  129. *
  130. * <p>Per default, Starling handles the Stage3D context independently. If you want to combine
  131. * Starling with another Stage3D engine, however, this may not be what you want. In this case,
  132. * you can make use of the <code>shareContext</code> property:</p>
  133. *
  134. * <ol>
  135. * <li>Manually create and configure a context3D object that both frameworks can work with
  136. * (through <code>stage3D.requestContext3D</code> and
  137. * <code>context.configureBackBuffer</code>).</li>
  138. * <li>Initialize Starling with the stage3D instance that contains that configured context.
  139. * This will automatically enable <code>shareContext</code>.</li>
  140. * <li>Call <code>start()</code> on your Starling instance (as usual). This will make
  141. * Starling queue input events (keyboard/mouse/touch).</li>
  142. * <li>Create a game loop (e.g. using the native <code>ENTER_FRAME</code> event) and let it
  143. * call Starling's <code>nextFrame</code> as well as the equivalent method of the other
  144. * Stage3D engine. Surround those calls with <code>context.clear()</code> and
  145. * <code>context.present()</code>.</li>
  146. * </ol>
  147. *
  148. * <p>The Starling wiki contains a <a href="http://goo.gl/BsXzw">tutorial</a> with more
  149. * information about this topic.</p>
  150. *
  151. */
  152. public class Starling extends EventDispatcher {
  153. /** The version of the Starling framework. */
  154. public static const VERSION:String = "1.4.1";
  155.  
  156. /** The key for the shader programs stored in 'contextData' */
  157. private static const PROGRAM_DATA_NAME:String = "Starling.programs";
  158.  
  159. // members
  160.  
  161. private var mStage3D:Stage3D;
  162. private var mStage:Stage; // starling.display.stage!
  163. private var mRootClass:Class;
  164. private var mRoot:DisplayObject;
  165. private var mJuggler:Juggler;
  166. private var mSupport:RenderSupport;
  167. private var mTouchProcessor:TouchProcessor;
  168. private var mAntiAliasing:int;
  169. private var mSimulateMultitouch:Boolean;
  170. private var mEnableErrorChecking:Boolean;
  171. private var mLastFrameTimestamp:Number;
  172. private var mLeftMouseDown:Boolean;
  173. private var mStatsDisplay:StatsDisplay;
  174. private var mShareContext:Boolean;
  175. private var mProfile:String;
  176. private var mSupportHighResolutions:Boolean;
  177. private var mContext:Context3D;
  178. private var mStarted:Boolean;
  179. private var mRendering:Boolean;
  180.  
  181. private var mViewPort:Rectangle;
  182. private var mPreviousViewPort:Rectangle;
  183. private var mClippedViewPort:Rectangle;
  184.  
  185. private var mNativeStage:flash.display.Stage;
  186. private var mNativeOverlay:Sprite;
  187. private var mNativeStageContentScaleFactor:Number;
  188.  
  189. private static var sCurrent:Starling;
  190. private static var sHandleLostContext:Boolean;
  191. private static var sContextData:Dictionary = new Dictionary(true);
  192.  
  193. // construction
  194.  
  195. /** Creates a new Starling instance.
  196. * @param rootClass A subclass of a Starling display object. It will be created as soon as
  197. * initialization is finished and will become the first child of the
  198. * Starling stage.
  199. * @param stage The Flash (2D) stage.
  200. * @param viewPort A rectangle describing the area into which the content will be
  201. * rendered. @default stage size
  202. * @param stage3D The Stage3D object into which the content will be rendered. If it
  203. * already contains a context, <code>sharedContext</code> will be set
  204. * to <code>true</code>. @default the first available Stage3D.
  205. * @param renderMode Use this parameter to force "software" rendering.
  206. * @param profile The Context3DProfile that should be requested.
  207. */
  208. public function Starling(rootClass:Class, stage:flash.display.Stage, viewPort:Rectangle = null, stage3D:Stage3D = null, renderMode:String = "auto", profile:String = "baselineConstrained") {
  209. if (stage == null) throw new ArgumentError("Stage must not be null");
  210. if (rootClass == null) throw new ArgumentError("Root class must not be null");
  211. if (viewPort == null) viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
  212. if (stage3D == null) stage3D = stage.stage3Ds[0];
  213.  
  214. makeCurrent();
  215.  
  216. mRootClass = rootClass;
  217. mViewPort = viewPort;
  218. mPreviousViewPort = new Rectangle();
  219. mStage3D = stage3D;
  220. mStage = new Stage(viewPort.width, viewPort.height, stage.color);
  221. mNativeOverlay = new Sprite();
  222. mNativeStage = stage;
  223. mNativeStage.addChild(mNativeOverlay);
  224. mNativeStageContentScaleFactor = 1.0;
  225. mTouchProcessor = new TouchProcessor(mStage);
  226. mJuggler = new Juggler();
  227. mAntiAliasing = 0;
  228. mSimulateMultitouch = false;
  229. mEnableErrorChecking = false;
  230. mProfile = profile;
  231. mSupportHighResolutions = false;
  232. mLastFrameTimestamp = getTimer() / 1000.0;
  233. mSupport = new RenderSupport();
  234.  
  235. // for context data, we actually reference by stage3D, since it survives a context loss
  236. sContextData[stage3D] = new Dictionary();
  237. sContextData[stage3D][PROGRAM_DATA_NAME] = new Dictionary();
  238.  
  239. // all other modes are problematic in Starling, so we force those here
  240. stage.scaleMode = StageScaleMode.NO_SCALE;
  241. stage.align = StageAlign.TOP_LEFT;
  242.  
  243. // register touch/mouse event handlers
  244. for each (var touchEventType:String in touchEventTypes)
  245. stage.addEventListener(touchEventType, onTouch, false, 0, true);
  246.  
  247. // register other event handlers
  248. stage.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
  249. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey, false, 0, true);
  250. stage.addEventListener(KeyboardEvent.KEY_UP, onKey, false, 0, true);
  251. stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
  252. stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave, false, 0, true);
  253.  
  254. mStage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 10, true);
  255. mStage3D.addEventListener(ErrorEvent.ERROR, onStage3DError, false, 10, true);
  256.  
  257. if (mStage3D.context3D && mStage3D.context3D.driverInfo != "Disposed") {
  258. mShareContext = true;
  259. setTimeout(initialize, 1); // we don't call it right away, because Starling should
  260. // behave the same way with or without a shared context
  261. }
  262. else {
  263. mShareContext = false;
  264.  
  265. try {
  266. // "Context3DProfile" is only available starting with Flash Player 11.4/AIR 3.4.
  267. // to stay compatible with older versions, we check if the parameter is available.
  268.  
  269. var requestContext3D:Function = mStage3D.requestContext3D;
  270. if (requestContext3D.length == 1) requestContext3D(renderMode);
  271. else requestContext3D(renderMode, profile);
  272. }
  273. catch (e:Error) {
  274. showFatalError("Context3D error: " + e.message);
  275. }
  276. }
  277. }
  278.  
  279. /** Disposes all children of the stage and the render context; removes all registered
  280. * event listeners. */
  281. public function dispose():void {
  282. stop(true);
  283.  
  284. mNativeStage.removeEventListener(Event.ENTER_FRAME, onEnterFrame, false);
  285. mNativeStage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey, false);
  286. mNativeStage.removeEventListener(KeyboardEvent.KEY_UP, onKey, false);
  287. mNativeStage.removeEventListener(Event.RESIZE, onResize, false);
  288. mNativeStage.removeEventListener(Event.MOUSE_LEAVE, onMouseLeave, false);
  289. mNativeStage.removeChild(mNativeOverlay);
  290.  
  291. mStage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false);
  292. mStage3D.removeEventListener(ErrorEvent.ERROR, onStage3DError, false);
  293.  
  294. for each (var touchEventType:String in touchEventTypes)
  295. mNativeStage.removeEventListener(touchEventType, onTouch, false);
  296.  
  297. if (mStage) mStage.dispose();
  298. if (mSupport) mSupport.dispose();
  299. if (mTouchProcessor) mTouchProcessor.dispose();
  300. if (sCurrent == this) sCurrent = null;
  301. if (mContext && !mShareContext) {
  302. // Per default, the context is recreated as long as there are listeners on it.
  303. // Beginning with AIR 3.6, we can avoid that with an additional parameter.
  304.  
  305. var disposeContext3D:Function = mContext.dispose;
  306. if (disposeContext3D.length == 1) disposeContext3D(false);
  307. else disposeContext3D();
  308. }
  309. }
  310.  
  311. // functions
  312.  
  313. private function initialize():void {
  314. makeCurrent();
  315.  
  316. initializeGraphicsAPI();
  317. initializeRoot();
  318.  
  319. mTouchProcessor.simulateMultitouch = mSimulateMultitouch;
  320. mLastFrameTimestamp = getTimer() / 1000.0;
  321. }
  322.  
  323. private function initializeGraphicsAPI():void {
  324. mContext = mStage3D.context3D;
  325. mContext.enableErrorChecking = mEnableErrorChecking;
  326. contextData[PROGRAM_DATA_NAME] = new Dictionary();
  327.  
  328. updateViewPort(true);
  329.  
  330. trace("[Starling] Initialization complete.");
  331. trace("[Starling] Display Driver:", mContext.driverInfo);
  332.  
  333. dispatchEventWith(starling.events.Event.CONTEXT3D_CREATE, false, mContext);
  334. }
  335.  
  336. private function initializeRoot():void {
  337. if (mRoot == null) {
  338. mRoot = new mRootClass() as DisplayObject;
  339. if (mRoot == null) throw new Error("Invalid root class: " + mRootClass);
  340. mStage.addChildAt(mRoot, 0);
  341.  
  342. dispatchEventWith(starling.events.Event.ROOT_CREATED, false, mRoot);
  343. }
  344. }
  345.  
  346. /** Calls <code>advanceTime()</code> (with the time that has passed since the last frame)
  347. * and <code>render()</code>. */
  348. public function nextFrame():void {
  349. var now:Number = getTimer() / 1000.0;
  350. var passedTime:Number = now - mLastFrameTimestamp;
  351. mLastFrameTimestamp = now;
  352.  
  353. advanceTime(passedTime);
  354. render();
  355. }
  356.  
  357. /** Dispatches ENTER_FRAME events on the display list, advances the Juggler
  358. * and processes touches. */
  359. public function advanceTime(passedTime:Number):void {
  360. makeCurrent();
  361.  
  362. mTouchProcessor.advanceTime(passedTime);
  363. mStage.advanceTime(passedTime);
  364. mJuggler.advanceTime(passedTime);
  365. }
  366.  
  367. /** Renders the complete display list. Before rendering, the context is cleared; afterwards,
  368. * it is presented. This can be avoided by enabling <code>shareContext</code>.*/
  369. public function render():void {
  370. if (!contextValid)
  371. return;
  372.  
  373. makeCurrent();
  374. updateViewPort();
  375. updateNativeOverlay();
  376.  
  377. mSupport.nextFrame();
  378.  
  379. if (!mShareContext)
  380. RenderSupport.clear(mStage.color, 1.0);
  381.  
  382. var scaleX:Number = mViewPort.width / mStage.stageWidth;
  383. var scaleY:Number = mViewPort.height / mStage.stageHeight;
  384.  
  385. mContext.setDepthTest(false, Context3DCompareMode.ALWAYS);
  386. mContext.setCulling(Context3DTriangleFace.NONE);
  387.  
  388. mSupport.renderTarget = null; // back buffer
  389. mSupport.setOrthographicProjection(
  390. mViewPort.x < 0 ? -mViewPort.x / scaleX : 0.0,
  391. mViewPort.y < 0 ? -mViewPort.y / scaleY : 0.0,
  392. mClippedViewPort.width / scaleX,
  393. mClippedViewPort.height / scaleY);
  394.  
  395. mStage.render(mSupport, 1.0);
  396. mSupport.finishQuadBatch();
  397.  
  398. if (mStatsDisplay)
  399. mStatsDisplay.drawCount = mSupport.drawCount;
  400.  
  401. if (!mShareContext)
  402. mContext.present();
  403. }
  404.  
  405. private function updateViewPort(forceUpdate:Boolean = false):void {
  406. // the last set viewport is stored in a variable; that way, people can modify the
  407. // viewPort directly (without a copy) and we still know if it has changed.
  408.  
  409. if (forceUpdate || mPreviousViewPort.width != mViewPort.width ||
  410. mPreviousViewPort.height != mViewPort.height ||
  411. mPreviousViewPort.x != mViewPort.x || mPreviousViewPort.y != mViewPort.y) {
  412. mPreviousViewPort.setTo(mViewPort.x, mViewPort.y, mViewPort.width, mViewPort.height);
  413.  
  414. // Constrained mode requires that the viewport is within the native stage bounds;
  415. // thus, we use a clipped viewport when configuring the back buffer. (In baseline
  416. // mode, that's not necessary, but it does not hurt either.)
  417.  
  418. mClippedViewPort = mViewPort.intersection(
  419. new Rectangle(0, 0, mNativeStage.stageWidth, mNativeStage.stageHeight));
  420.  
  421. if (!mShareContext) {
  422. // setting x and y might move the context to invalid bounds (since changing
  423. // the size happens in a separate operation) -- so we have no choice but to
  424. // set the backbuffer to a very small size first, to be on the safe side.
  425.  
  426. if (mProfile == "baselineConstrained")
  427. configureBackBuffer(32, 32, mAntiAliasing, false);
  428.  
  429. mStage3D.x = mClippedViewPort.x;
  430. mStage3D.y = mClippedViewPort.y;
  431.  
  432. configureBackBuffer(mClippedViewPort.width, mClippedViewPort.height,
  433. mAntiAliasing, false, mSupportHighResolutions);
  434.  
  435. if (mSupportHighResolutions && "contentsScaleFactor" in mNativeStage)
  436. mNativeStageContentScaleFactor = mNativeStage["contentsScaleFactor"];
  437. else
  438. mNativeStageContentScaleFactor = 1.0;
  439. }
  440. }
  441. }
  442.  
  443. /** Configures the back buffer while automatically keeping backwards compatibility with
  444. * AIR versions that do not support the "wantsBestResolution" argument. */
  445. private function configureBackBuffer(width:int, height:int, antiAlias:int, enableDepthAndStencil:Boolean, wantsBestResolution:Boolean = false):void {
  446. var configureBackBuffer:Function = mContext.configureBackBuffer;
  447. var methodArgs:Array = [width, height, antiAlias, enableDepthAndStencil];
  448. if (configureBackBuffer.length > 4) methodArgs.push(wantsBestResolution);
  449. configureBackBuffer.apply(mContext, methodArgs);
  450. }
  451.  
  452. private function updateNativeOverlay():void {
  453. mNativeOverlay.x = mViewPort.x;
  454. mNativeOverlay.y = mViewPort.y;
  455. mNativeOverlay.scaleX = mViewPort.width / mStage.stageWidth;
  456. mNativeOverlay.scaleY = mViewPort.height / mStage.stageHeight;
  457. }
  458.  
  459. private function showFatalError(message:String):void {
  460. var textField:TextField = new TextField();
  461. var textFormat:TextFormat = new TextFormat("Verdana", 12, 0xFFFFFF);
  462. textFormat.align = TextFormatAlign.CENTER;
  463. textField.defaultTextFormat = textFormat;
  464. textField.wordWrap = true;
  465. textField.width = mStage.stageWidth * 0.75;
  466. textField.autoSize = TextFieldAutoSize.CENTER;
  467. textField.text = message;
  468. textField.x = (mStage.stageWidth - textField.width) / 2;
  469. textField.y = (mStage.stageHeight - textField.height) / 2;
  470. textField.background = true;
  471. textField.backgroundColor = 0x440000;
  472. nativeOverlay.addChild(textField);
  473. }
  474.  
  475. /** Make this Starling instance the <code>current</code> one. */
  476. public function makeCurrent():void {
  477. sCurrent = this;
  478. }
  479.  
  480. /** As soon as Starling is started, it will queue input events (keyboard/mouse/touch);
  481. * furthermore, the method <code>nextFrame</code> will be called once per Flash Player
  482. * frame. (Except when <code>shareContext</code> is enabled: in that case, you have to
  483. * call that method manually.) */
  484. public function start():void {
  485. mStarted = mRendering = true;
  486. mLastFrameTimestamp = getTimer() / 1000.0;
  487. }
  488.  
  489. /** Stops all logic and input processing, effectively freezing the app in its current state.
  490. * Per default, rendering will continue: that's because the classic display list
  491. * is only updated when stage3D is. (If Starling stopped rendering, conventional Flash
  492. * contents would freeze, as well.)
  493. *
  494. * <p>However, if you don't need classic Flash contents, you can stop rendering, too.
  495. * On some mobile systems (e.g. iOS), you are even required to do so if you have
  496. * activated background code execution.</p>
  497. */
  498. public function stop(suspendRendering:Boolean = false):void {
  499. mStarted = false;
  500. mRendering = !suspendRendering;
  501. }
  502.  
  503. // event handlers
  504.  
  505. private function onStage3DError(event:ErrorEvent):void {
  506. if (event.errorID == 3702) {
  507. var mode:String = Capabilities.playerType == "Desktop" ? "renderMode" : "wmode";
  508. showFatalError("Context3D not available! Possible reasons: wrong " + mode +
  509. " or missing device support.");
  510. }
  511. else
  512. showFatalError("Stage3D error: " + event.text);
  513. }
  514.  
  515. private function onContextCreated(event:Event):void {
  516. if (!Starling.handleLostContext && mContext) {
  517. stop();
  518. event.stopImmediatePropagation();
  519. showFatalError("Fatal error: The application lost the device context!");
  520. trace("[Starling] The device context was lost. " +
  521. "Enable 'Starling.handleLostContext' to avoid this error.");
  522. }
  523. else {
  524. initialize();
  525. }
  526. }
  527.  
  528. private function onEnterFrame(event:Event):void {
  529. // On mobile, the native display list is only updated on stage3D draw calls.
  530. // Thus, we render even when Starling is paused.
  531.  
  532. if (!mShareContext) {
  533. if (mStarted) nextFrame();
  534. else if (mRendering) render();
  535. }
  536. }
  537.  
  538. private function onKey(event:KeyboardEvent):void {
  539. if (!mStarted) return;
  540.  
  541. var keyEvent:starling.events.KeyboardEvent = new starling.events.KeyboardEvent(
  542. event.type, event.charCode, event.keyCode, event.keyLocation,
  543. event.ctrlKey, event.altKey, event.shiftKey);
  544.  
  545. makeCurrent();
  546. mStage.broadcastEvent(keyEvent);
  547.  
  548. if (keyEvent.isDefaultPrevented())
  549. event.preventDefault();
  550. }
  551.  
  552. private function onResize(event:Event):void {
  553. var stage:flash.display.Stage = event.target as flash.display.Stage;
  554. mStage.dispatchEvent(new ResizeEvent(Event.RESIZE, stage.stageWidth, stage.stageHeight));
  555. }
  556.  
  557. private function onMouseLeave(event:Event):void {
  558. mTouchProcessor.enqueueMouseLeftStage();
  559. }
  560.  
  561. private function onTouch(event:Event):void {
  562. if (!mStarted) return;
  563.  
  564. var globalX:Number;
  565. var globalY:Number;
  566. var touchID:int;
  567. var phase:String;
  568. var pressure:Number = 1.0;
  569. var width:Number = 1.0;
  570. var height:Number = 1.0;
  571.  
  572. // figure out general touch properties
  573. if (event is MouseEvent) {
  574. var mouseEvent:MouseEvent = event as MouseEvent;
  575. globalX = mouseEvent.stageX;
  576. globalY = mouseEvent.stageY;
  577. touchID = 0;
  578.  
  579. // MouseEvent.buttonDown returns true for both left and right button (AIR supports
  580. // the right mouse button). We only want to react on the left button for now,
  581. // so we have to save the state for the left button manually.
  582. if (event.type == MouseEvent.MOUSE_DOWN) mLeftMouseDown = true;
  583. else if (event.type == MouseEvent.MOUSE_UP) mLeftMouseDown = false;
  584. }
  585. else {
  586. var touchEvent:TouchEvent = event as TouchEvent;
  587.  
  588. // On a system that supports both mouse and touch input, the primary touch point
  589. // is dispatched as mouse event as well. Since we don't want to listen to that
  590. // event twice, we ignore the primary touch in that case.
  591.  
  592. if (Mouse.supportsCursor && touchEvent.isPrimaryTouchPoint) return;
  593. else {
  594. globalX = touchEvent.stageX;
  595. globalY = touchEvent.stageY;
  596. touchID = touchEvent.touchPointID;
  597. pressure = touchEvent.pressure;
  598. width = touchEvent.sizeX;
  599. height = touchEvent.sizeY;
  600. }
  601. }
  602.  
  603. // figure out touch phase
  604. switch (event.type) {
  605. case TouchEvent.TOUCH_BEGIN:
  606. phase = TouchPhase.BEGAN;
  607. break;
  608. case TouchEvent.TOUCH_MOVE:
  609. phase = TouchPhase.MOVED;
  610. break;
  611. case TouchEvent.TOUCH_END:
  612. phase = TouchPhase.ENDED;
  613. break;
  614. case MouseEvent.MOUSE_DOWN:
  615. phase = TouchPhase.BEGAN;
  616. break;
  617. case MouseEvent.MOUSE_UP:
  618. phase = TouchPhase.ENDED;
  619. break;
  620. case MouseEvent.MOUSE_MOVE:
  621. phase = (mLeftMouseDown ? TouchPhase.MOVED : TouchPhase.HOVER);
  622. break;
  623. }
  624.  
  625. // move position into viewport bounds
  626. globalX = mStage.stageWidth * (globalX - mViewPort.x) / mViewPort.width;
  627. globalY = mStage.stageHeight * (globalY - mViewPort.y) / mViewPort.height;
  628.  
  629. // enqueue touch in touch processor
  630. mTouchProcessor.enqueue(touchID, phase, globalX, globalY, pressure, width, height);
  631.  
  632. // allow objects that depend on mouse-over state to be updated immediately
  633. if (event.type == MouseEvent.MOUSE_UP)
  634. mTouchProcessor.enqueue(touchID, TouchPhase.HOVER, globalX, globalY);
  635. }
  636.  
  637. private function get touchEventTypes():Array {
  638. var types:Array = [];
  639.  
  640. if (multitouchEnabled)
  641. types.push(TouchEvent.TOUCH_BEGIN, TouchEvent.TOUCH_MOVE, TouchEvent.TOUCH_END);
  642.  
  643. if (!multitouchEnabled || Mouse.supportsCursor)
  644. types.push(MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_MOVE, MouseEvent.MOUSE_UP);
  645.  
  646. return types;
  647. }
  648.  
  649. // program management
  650.  
  651. /** Registers a compiled shader-program under a certain name.
  652. * If the name was already used, the previous program is overwritten. */
  653. public function registerProgram(name:String, vertexShader:ByteArray, fragmentShader:ByteArray):Program3D {
  654. deleteProgram(name);
  655.  
  656. var program:Program3D = mContext.createProgram();
  657. program.upload(vertexShader, fragmentShader);
  658. programs[name] = program;
  659.  
  660. return program;
  661. }
  662.  
  663. /** Compiles a shader-program and registers it under a certain name.
  664. * If the name was already used, the previous program is overwritten. */
  665. public function registerProgramFromSource(name:String, vertexShader:String, fragmentShader:String):Program3D {
  666. deleteProgram(name);
  667.  
  668. var program:Program3D = RenderSupport.assembleAgal(vertexShader, fragmentShader);
  669. programs[name] = program;
  670.  
  671. return program;
  672. }
  673.  
  674. /** Deletes the vertex- and fragment-programs of a certain name. */
  675. public function deleteProgram(name:String):void {
  676. var program:Program3D = getProgram(name);
  677. if (program) {
  678. program.dispose();
  679. delete programs[name];
  680. }
  681. }
  682.  
  683. /** Returns the vertex- and fragment-programs registered under a certain name. */
  684. public function getProgram(name:String):Program3D {
  685. return programs[name] as Program3D;
  686. }
  687.  
  688. /** Indicates if a set of vertex- and fragment-programs is registered under a certain name. */
  689. public function hasProgram(name:String):Boolean {
  690. return name in programs;
  691. }
  692.  
  693. private function get programs():Dictionary {
  694. return contextData[PROGRAM_DATA_NAME];
  695. }
  696.  
  697. // properties
  698.  
  699. /** Indicates if a context is available and non-disposed. */
  700. private function get contextValid():Boolean {
  701. return (mContext && mContext.driverInfo != "Disposed");
  702. }
  703.  
  704. /** Indicates if this Starling instance is started. */
  705. public function get isStarted():Boolean {
  706. return mStarted;
  707. }
  708.  
  709. /** The default juggler of this instance. Will be advanced once per frame. */
  710. public function get juggler():Juggler {
  711. return mJuggler;
  712. }
  713.  
  714. /** The render context of this instance. */
  715. public function get context():Context3D {
  716. return mContext;
  717. }
  718.  
  719. /** A dictionary that can be used to save custom data related to the current context.
  720. * If you need to share data that is bound to a specific stage3D instance
  721. * (e.g. textures), use this dictionary instead of creating a static class variable.
  722. * The Dictionary is actually bound to the stage3D instance, thus it survives a
  723. * context loss. */
  724. public function get contextData():Dictionary {
  725. return sContextData[mStage3D] as Dictionary;
  726. }
  727.  
  728. /** Returns the actual width (in pixels) of the back buffer. This can differ from the
  729. * width of the viewPort rectangle if it is partly outside the native stage. */
  730. public function get backBufferWidth():int {
  731. return mClippedViewPort.width;
  732. }
  733.  
  734. /** Returns the actual height (in pixels) of the back buffer. This can differ from the
  735. * height of the viewPort rectangle if it is partly outside the native stage. */
  736. public function get backBufferHeight():int {
  737. return mClippedViewPort.height;
  738. }
  739.  
  740. /** Indicates if multitouch simulation with "Shift" and "Ctrl"/"Cmd"-keys is enabled.
  741. * @default false */
  742. public function get simulateMultitouch():Boolean {
  743. return mSimulateMultitouch;
  744. }
  745.  
  746. public function set simulateMultitouch(value:Boolean):void {
  747. mSimulateMultitouch = value;
  748. if (mContext) mTouchProcessor.simulateMultitouch = value;
  749. }
  750.  
  751. /** Indicates if Stage3D render methods will report errors. Activate only when needed,
  752. * as this has a negative impact on performance. @default false */
  753. public function get enableErrorChecking():Boolean {
  754. return mEnableErrorChecking;
  755. }
  756.  
  757. public function set enableErrorChecking(value:Boolean):void {
  758. mEnableErrorChecking = value;
  759. if (mContext) mContext.enableErrorChecking = value;
  760. }
  761.  
  762. /** The antialiasing level. 0 - no antialasing, 16 - maximum antialiasing. @default 0 */
  763. public function get antiAliasing():int {
  764. return mAntiAliasing;
  765. }
  766.  
  767. public function set antiAliasing(value:int):void {
  768. if (mAntiAliasing != value) {
  769. mAntiAliasing = value;
  770. if (contextValid) updateViewPort(true);
  771. }
  772. }
  773.  
  774. /** The viewport into which Starling contents will be rendered. */
  775. public function get viewPort():Rectangle {
  776. return mViewPort;
  777. }
  778.  
  779. public function set viewPort(value:Rectangle):void {
  780. mViewPort = value.clone();
  781. }
  782.  
  783. /** The ratio between viewPort width and stage width. Useful for choosing a different
  784. * set of textures depending on the display resolution. */
  785. public function get contentScaleFactor():Number {
  786. return (mViewPort.width * mNativeStageContentScaleFactor) / mStage.stageWidth;
  787. }
  788.  
  789. /** A Flash Sprite placed directly on top of the Starling content. Use it to display native
  790. * Flash components. */
  791. public function get nativeOverlay():Sprite {
  792. return mNativeOverlay;
  793. }
  794.  
  795. /** Indicates if a small statistics box (with FPS, memory usage and draw count) is displayed. */
  796. public function get showStats():Boolean {
  797. return mStatsDisplay && mStatsDisplay.parent;
  798. }
  799.  
  800. public function set showStats(value:Boolean):void {
  801. if (value == showStats) return;
  802.  
  803. if (value) {
  804. if (mStatsDisplay) mStage.addChild(mStatsDisplay);
  805. else showStatsAt();
  806. }
  807. else mStatsDisplay.removeFromParent();
  808. }
  809.  
  810. /** Displays the statistics box at a certain position. */
  811. public function showStatsAt(hAlign:String = "left", vAlign:String = "top", scale:Number = 1):void {
  812. if (mContext == null) {
  813. // Starling is not yet ready - we postpone this until it's initialized.
  814. addEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
  815. }
  816. else {
  817. if (mStatsDisplay == null) {
  818. mStatsDisplay = new StatsDisplay();
  819. mStatsDisplay.touchable = false;
  820. mStage.addChild(mStatsDisplay);
  821. }
  822.  
  823. var stageWidth:int = mStage.stageWidth;
  824. var stageHeight:int = mStage.stageHeight;
  825.  
  826. mStatsDisplay.scaleX = mStatsDisplay.scaleY = scale;
  827.  
  828. if (hAlign == HAlign.LEFT) mStatsDisplay.x = 0;
  829. else if (hAlign == HAlign.RIGHT) mStatsDisplay.x = stageWidth - mStatsDisplay.width;
  830. else mStatsDisplay.x = int((stageWidth - mStatsDisplay.width) / 2);
  831.  
  832. if (vAlign == VAlign.TOP) mStatsDisplay.y = 0;
  833. else if (vAlign == VAlign.BOTTOM) mStatsDisplay.y = stageHeight - mStatsDisplay.height;
  834. else mStatsDisplay.y = int((stageHeight - mStatsDisplay.height) / 2);
  835. }
  836.  
  837. function onRootCreated():void {
  838. showStatsAt(hAlign, vAlign, scale);
  839. removeEventListener(starling.events.Event.ROOT_CREATED, onRootCreated);
  840. }
  841. }
  842.  
  843. /** The Starling stage object, which is the root of the display tree that is rendered. */
  844. public function get stage():Stage {
  845. return mStage;
  846. }
  847.  
  848. /** The Flash Stage3D object Starling renders into. */
  849. public function get stage3D():Stage3D {
  850. return mStage3D;
  851. }
  852.  
  853. /** The Flash (2D) stage object Starling renders beneath. */
  854. public function get nativeStage():flash.display.Stage {
  855. return mNativeStage;
  856. }
  857.  
  858. /** The instance of the root class provided in the constructor. Available as soon as
  859. * the event 'ROOT_CREATED' has been dispatched. */
  860. public function get root():DisplayObject {
  861. return mRoot;
  862. }
  863.  
  864. /** Indicates if the Context3D render calls are managed externally to Starling,
  865. * to allow other frameworks to share the Stage3D instance. @default false */
  866. public function get shareContext():Boolean {
  867. return mShareContext;
  868. }
  869.  
  870. public function set shareContext(value:Boolean):void {
  871. mShareContext = value;
  872. }
  873.  
  874. /** The Context3D profile as requested in the constructor. Beware that if you are
  875. * using a shared context, this might not be accurate. */
  876. public function get profile():String {
  877. return mProfile;
  878. }
  879.  
  880. /** Indicates that if the device supports HiDPI screens Starling will attempt to allocate
  881. * a larger back buffer than indicated via the viewPort size. Note that this is used
  882. * on Desktop only; mobile AIR apps still use the "requestedDisplayResolution" parameter
  883. * the application descriptor XML. */
  884. public function get supportHighResolutions():Boolean {
  885. return mSupportHighResolutions;
  886. }
  887.  
  888. public function set supportHighResolutions(value:Boolean):void {
  889. if (mSupportHighResolutions != value) {
  890. mSupportHighResolutions = value;
  891. if (contextValid) updateViewPort(true);
  892. }
  893. }
  894.  
  895. /** The TouchProcessor is passed all mouse and touch input and is responsible for
  896. * dispatching TouchEvents to the Starling display tree. If you want to handle these
  897. * types of input manually, pass your own custom subclass to this property. */
  898. public function get touchProcessor():TouchProcessor {
  899. return mTouchProcessor;
  900. }
  901.  
  902. public function set touchProcessor(value:TouchProcessor):void {
  903. if (value != mTouchProcessor) {
  904. mTouchProcessor.dispose();
  905. mTouchProcessor = value;
  906. }
  907. }
  908.  
  909. // static properties
  910.  
  911. /** The currently active Starling instance. */
  912. public static function get current():Starling {
  913. return sCurrent;
  914. }
  915.  
  916. /** The render context of the currently active Starling instance. */
  917. public static function get context():Context3D {
  918. return sCurrent ? sCurrent.context : null;
  919. }
  920.  
  921. /** The default juggler of the currently active Starling instance. */
  922. public static function get juggler():Juggler {
  923. return sCurrent ? sCurrent.juggler : null;
  924. }
  925.  
  926. /** The contentScaleFactor of the currently active Starling instance. */
  927. public static function get contentScaleFactor():Number {
  928. return sCurrent ? sCurrent.contentScaleFactor : 1.0;
  929. }
  930.  
  931. /** Indicates if multitouch input should be supported. */
  932. public static function get multitouchEnabled():Boolean {
  933. return Multitouch.inputMode == MultitouchInputMode.TOUCH_POINT;
  934. }
  935.  
  936. public static function set multitouchEnabled(value:Boolean):void {
  937. if (sCurrent) throw new IllegalOperationError(
  938. "'multitouchEnabled' must be set before Starling instance is created");
  939. else
  940. Multitouch.inputMode = value ? MultitouchInputMode.TOUCH_POINT :
  941. MultitouchInputMode.NONE;
  942. }
  943.  
  944. /** Indicates if Starling should automatically recover from a lost device context.
  945. * On some systems, an upcoming screensaver or entering sleep mode may
  946. * invalidate the render context. This setting indicates if Starling should recover from
  947. * such incidents. Beware that this has a huge impact on memory consumption!
  948. * It is recommended to enable this setting on Android and Windows, but to deactivate it
  949. * on iOS and Mac OS X. @default false */
  950. public static function get handleLostContext():Boolean {
  951. return sHandleLostContext;
  952. }
  953.  
  954. public static function set handleLostContext(value:Boolean):void {
  955. if (sCurrent) throw new IllegalOperationError(
  956. "'handleLostContext' must be set before Starling instance is created");
  957. else
  958. sHandleLostContext = value;
  959. }
  960. }
  961. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement