scaffold.libs_as.starling.textures.RenderTexture.as Maven / Gradle / Ivy
// =================================================================================================
//
// Starling Framework
// Copyright 2011-2015 Gamua. 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.textures
{
import flash.display3D.textures.TextureBase;
import flash.errors.IllegalOperationError;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import starling.core.Starling;
import starling.display.BlendMode;
import starling.display.DisplayObject;
import starling.display.Image;
import starling.filters.FragmentFilter;
import starling.rendering.Painter;
import starling.rendering.RenderState;
import starling.utils.execute;
/** A RenderTexture is a dynamic texture onto which you can draw any display object.
*
* After creating a render texture, just call the drawObject
method to render
* an object directly onto the texture. The object will be drawn onto the texture at its current
* position, adhering its current rotation, scale and alpha properties.
*
* Drawing is done very efficiently, as it is happening directly in graphics memory. After
* you have drawn objects onto the texture, the performance will be just like that of a normal
* texture - no matter how many objects you have drawn.
*
* If you draw lots of objects at once, it is recommended to bundle the drawing calls in
* a block via the drawBundled
method, like shown below. That will speed it up
* immensely, allowing you to draw hundreds of objects very quickly.
*
*
* renderTexture.drawBundled(function():void
* {
* for (var i:int=0; i<numDrawings; ++i)
* {
* image.rotation = (2 * Math.PI / numDrawings) * i;
* renderTexture.draw(image);
* }
* });
*
*
* To erase parts of a render texture, you can use any display object like a "rubber" by
* setting its blending mode to "BlendMode.ERASE".
*
* Beware that render textures can't be restored when the Starling's render context is lost.
*
*
* Persistence
*
* Older devices may require double buffering to support persistent render textures. Thus,
* you should disable the persistent
parameter in the constructor if you only
* need to make one draw operation on the texture. The static useDoubleBuffering
* property allows you to customize if new textures will be created with or without double
* buffering.
*/
public class RenderTexture extends SubTexture
{
private static const USE_DOUBLE_BUFFERING_DATA_NAME:String =
"starling.textures.RenderTexture.useDoubleBuffering";
private var _activeTexture:Texture;
private var _bufferTexture:Texture;
private var _helperImage:Image;
private var _drawing:Boolean;
private var _bufferReady:Boolean;
private var _isPersistent:Boolean;
// helper object
private static var sClipRect:Rectangle = new Rectangle();
/** Creates a new RenderTexture with a certain size (in points). If the texture is
* persistent, its contents remains intact after each draw call, allowing you to use the
* texture just like a canvas. If it is not, it will be cleared before each draw call.
*
* Non-persistent textures can be used more efficiently on older devices; on modern
* hardware, it does not make a difference. For more information, have a look at the
* documentation of the useDoubleBuffering
property.
*/
public function RenderTexture(width:int, height:int, persistent:Boolean=true,
scale:Number=-1, format:String="bgra")
{
_isPersistent = persistent;
_activeTexture = Texture.empty(width, height, true, false, true, scale, format);
_activeTexture.root.onRestore = _activeTexture.root.clear;
super(_activeTexture, new Rectangle(0, 0, width, height), true, null, false);
if (persistent && useDoubleBuffering)
{
_bufferTexture = Texture.empty(width, height, true, false, true, scale, format);
_bufferTexture.root.onRestore = _bufferTexture.root.clear;
_helperImage = new Image(_bufferTexture);
_helperImage.textureSmoothing = TextureSmoothing.NONE; // solves some aliasing-issues
}
}
/** @inheritDoc */
public override function dispose():void
{
_activeTexture.dispose();
if (isDoubleBuffered)
{
_bufferTexture.dispose();
_helperImage.dispose();
}
super.dispose();
}
/** Draws an object into the texture. Note that any filters on the object will currently
* be ignored.
*
* @param object The object to draw.
* @param matrix If 'matrix' is null, the object will be drawn adhering its
* properties for position, scale, and rotation. If it is not null,
* the object will be drawn in the orientation depicted by the matrix.
* @param alpha The object's alpha value will be multiplied with this value.
* @param antiAliasing Only supported on Desktop.
* Values range from 0 (no anti-aliasing) to 4 (best quality).
*/
public function draw(object:DisplayObject, matrix:Matrix=null, alpha:Number=1.0,
antiAliasing:int=0):void
{
if (object == null) return;
if (_drawing)
render(object, matrix, alpha);
else
renderBundled(render, object, matrix, alpha, antiAliasing);
}
/** Bundles several calls to draw
together in a block. This avoids buffer
* switches and allows you to draw multiple objects into a non-persistent texture.
* Note that the 'antiAliasing' setting provided here overrides those provided in
* individual 'draw' calls.
*
* @param drawingBlock a callback with the form: function():void;
* @param antiAliasing Only supported beginning with AIR 13, and only on Desktop.
* Values range from 0 (no antialiasing) to 4 (best quality). */
public function drawBundled(drawingBlock:Function, antiAliasing:int=0):void
{
renderBundled(drawingBlock, null, null, 1.0, antiAliasing);
}
private function render(object:DisplayObject, matrix:Matrix=null, alpha:Number=1.0):void
{
var painter:Painter = Starling.painter;
var state:RenderState = painter.state;
var filter:FragmentFilter = object.filter;
var mask:DisplayObject = object.mask;
painter.pushState();
state.alpha *= alpha;
state.setModelviewMatricesToIdentity();
state.blendMode = object.blendMode == BlendMode.AUTO ?
BlendMode.NORMAL : object.blendMode;
if (matrix) state.transformModelviewMatrix(matrix);
else state.transformModelviewMatrix(object.transformationMatrix);
if (mask) painter.drawMask(mask);
if (filter) filter.render(painter);
else object.render(painter);
if (mask) painter.eraseMask(mask);
painter.popState();
}
private function renderBundled(renderBlock:Function, object:DisplayObject=null,
matrix:Matrix=null, alpha:Number=1.0,
antiAliasing:int=0):void
{
var painter:Painter = Starling.painter;
var state:RenderState = painter.state;
if (!Starling.current.contextValid) return;
// switch buffers
if (isDoubleBuffered)
{
var tmpTexture:Texture = _activeTexture;
_activeTexture = _bufferTexture;
_bufferTexture = tmpTexture;
_helperImage.texture = _bufferTexture;
}
painter.pushState();
var rootTexture:Texture = _activeTexture.root;
state.setProjectionMatrix(0, 0, rootTexture.width, rootTexture.height, width, height);
// limit drawing to relevant area
sClipRect.setTo(0, 0, _activeTexture.width, _activeTexture.height);
state.clipRect = sClipRect;
state.setRenderTarget(_activeTexture, true, antiAliasing);
painter.prepareToDraw();
if (isDoubleBuffered || !isPersistent || !_bufferReady)
painter.clear();
// draw buffer
if (isDoubleBuffered && _bufferReady)
_helperImage.render(painter);
else
_bufferReady = true;
try
{
_drawing = true;
execute(renderBlock, object, matrix, alpha);
}
finally
{
_drawing = false;
painter.popState();
}
}
/** Clears the render texture with a certain color and alpha value. Call without any
* arguments to restore full transparency. */
public function clear(color:uint=0, alpha:Number=0.0):void
{
_activeTexture.root.clear(color, alpha);
_bufferReady = true;
}
// properties
/** Indicates if the render texture is using double buffering. This might be necessary for
* persistent textures, depending on the runtime version and the value of
* 'forceDoubleBuffering'. */
private function get isDoubleBuffered():Boolean { return _bufferTexture != null; }
/** Indicates if the texture is persistent over multiple draw calls. */
public function get isPersistent():Boolean { return _isPersistent; }
/** @inheritDoc */
public override function get base():TextureBase { return _activeTexture.base; }
/** @inheritDoc */
public override function get root():ConcreteTexture { return _activeTexture.root; }
/** Indicates if new persistent textures should use double buffering. Single buffering
* is faster and requires less memory, but is not supported on all hardware.
*
* By default, applications running with the profile "baseline" or "baselineConstrained"
* will use double buffering; all others use just a single buffer. You can override this
* behavior, though, by assigning a different value at runtime.
*
* @default true for "baseline" and "baselineConstrained", false otherwise
*/
public static function get useDoubleBuffering():Boolean
{
if (Starling.current)
{
var painter:Painter = Starling.painter;
var sharedData:Dictionary = painter.sharedData;
if (USE_DOUBLE_BUFFERING_DATA_NAME in sharedData)
{
return sharedData[USE_DOUBLE_BUFFERING_DATA_NAME];
}
else
{
var profile:String = painter.profile ? painter.profile : "baseline";
var value:Boolean = profile == "baseline" || profile == "baselineConstrained";
sharedData[USE_DOUBLE_BUFFERING_DATA_NAME] = value;
return value;
}
}
else return false;
}
public static function set useDoubleBuffering(value:Boolean):void
{
if (Starling.current == null)
throw new IllegalOperationError("Starling not yet initialized");
else
Starling.painter.sharedData[USE_DOUBLE_BUFFERING_DATA_NAME] = value;
}
}
}