// ================================================================================================= // // 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:
* *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).
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.
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.
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.
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:
RenderUtil.requestContext3D and
* context.configureBackBuffer).shareContext.start() on your Starling instance (as usual). This will make
* Starling queue input events (keyboard/mouse/touch).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.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.
*
* 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.
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().
*
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.
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, ornull
* 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.
CAUTION: not a copy, but the actual object! Do not modify!
*/ public static function get all():Vector.