All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scaffold.libs_as.starling.rendering.Effect.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.rendering
{
    import flash.display3D.Context3D;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.geom.Matrix3D;
    import flash.utils.Dictionary;
    import flash.utils.getQualifiedClassName;

    import starling.core.Starling;
    import starling.errors.MissingContextError;
    import starling.utils.execute;

    /** An effect encapsulates all steps of a Stage3D draw operation. It configures the
     *  render context and sets up shader programs as well as index- and vertex-buffers, thus
     *  providing the basic mechanisms of all low-level rendering.
     *
     *  

Using the Effect class

* *

Effects are mostly used by the MeshStyle and FragmentFilter * classes. When you extend those classes, you'll be required to provide a custom effect. * Setting it up for rendering is done by the base class, though, so you rarely have to * initiate the rendering yourself. Nevertheless, it's good to know how an effect is doing * its work.

* *

Using an effect always follows steps shown in the example below. You create the * effect, configure it, upload vertex data and then: draw!

* * * // create effect * var effect:MeshEffect = new MeshEffect(); * * // configure effect * effect.mvpMatrix3D = painter.state.mvpMatrix3D; * effect.texture = getHeroTexture(); * effect.color = 0xf0f0f0; * * // upload vertex data * effect.uploadIndexData(indexData); * effect.uploadVertexData(vertexData); * * // draw! * effect.render(0, numTriangles); * *

Note that the VertexData being uploaded has to be created with the same * format as the one returned by the effect's vertexFormat property.

* *

Extending the Effect class

* *

The base Effect-class can only render white triangles, which is not much * use in itself. However, it is designed to be extended; subclasses can easily implement any * kinds of shaders.

* *

Normally, you won't extend this class directly, but either FilterEffect * or MeshEffect, depending on your needs (i.e. if you want to create a new * fragment filter or a new mesh style). Whichever base class you're extending, you should * override the following methods:

* *
    *
  • createProgram():Program — must create the actual program containing * vertex- and fragment-shaders. A program will be created only once for each render * context; this is taken care of by the base class.
  • *
  • get programVariantName():uint (optional) — override this if your * effect requires different programs, depending on its settings. The recommended * way to do this is via a bit-mask that uniquely encodes the current settings.
  • *
  • get vertexFormat():String (optional) — must return the * VertexData format that this effect requires for its vertices. If * the effect does not require any special attributes, you can leave this out.
  • *
  • beforeDraw(context:Context3D):void — Set up your context by * configuring program constants and buffer attributes.
  • *
  • afterDraw(context:Context3D):void — Will be called directly after * context.drawTriangles(). Clean up any context configuration here.
  • *
* *

Furthermore, you need to add properties that manage the data you require on rendering, * e.g. the texture(s) that should be used, program constants, etc. I recommend looking at * the implementations of Starling's FilterEffect and MeshEffect * classes to see how to approach sub-classing.

* * @see FilterEffect * @see MeshEffect * @see starling.rendering.MeshStyle * @see starling.filters.FragmentFilter * @see starling.utils.RenderUtil */ public class Effect { /** The vertex format expected by uploadVertexData: * "position:float2" */ public static const VERTEX_FORMAT:VertexDataFormat = VertexDataFormat.fromString("position:float2"); private var _indexBuffer:IndexBuffer3D; private var _indexBufferSize:int; // in number of indices private var _vertexBuffer:VertexBuffer3D; private var _vertexBufferSize:int; // in blocks of 32 bits private var _mvpMatrix3D:Matrix3D; private var _onRestore:Function; private var _programBaseName:String; // helper objects private static var sProgramNameCache:Dictionary = new Dictionary(); /** Creates a new effect. */ public function Effect() { _mvpMatrix3D = new Matrix3D(); _programBaseName = getQualifiedClassName(this); // Handle lost context (using conventional Flash event for weak listener support) Starling.current.stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 0, true); } /** Purges the index- and vertex-buffers. */ public function dispose():void { Starling.current.stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated); purgeBuffers(); } private function onContextCreated(event:Event):void { purgeBuffers(); execute(_onRestore, this); } /** Purges one or both of the index- and vertex-buffers. */ public function purgeBuffers(indexBuffer:Boolean=true, vertexBuffer:Boolean=true):void { if (_indexBuffer && indexBuffer) { _indexBuffer.dispose(); _indexBuffer = null; } if (_vertexBuffer && vertexBuffer) { _vertexBuffer.dispose(); _vertexBuffer = null; } } /** Uploads the given index data to the internal index buffer. If the buffer is too * small, a new one is created automatically. */ public function uploadIndexData(indexData:IndexData):void { if (_indexBuffer) { if (indexData.numIndices <= _indexBufferSize) indexData.uploadToIndexBuffer(_indexBuffer); else purgeBuffers(true, false); } if (_indexBuffer == null) { _indexBuffer = indexData.createIndexBuffer(true); _indexBufferSize = indexData.numIndices; } } /** Uploads the given vertex data to the internal vertex buffer. If the buffer is too * small, a new one is created automatically. */ public function uploadVertexData(vertexData:VertexData):void { if (_vertexBuffer) { if (vertexData.sizeIn32Bits <= _vertexBufferSize) vertexData.uploadToVertexBuffer(_vertexBuffer); else purgeBuffers(false, true); } if (_vertexBuffer == null) { _vertexBuffer = vertexData.createVertexBuffer(true); _vertexBufferSize = vertexData.sizeIn32Bits; } } // rendering /** Draws the triangles described by the index- and vertex-buffers, or a range of them. * This calls beforeDraw, context.drawTriangles, and * afterDraw, in this order. */ public function render(firstIndex:int=0, numTriangles:int=-1):void { if (numTriangles < 0) numTriangles = indexBufferSize / 3; if (numTriangles == 0) return; var context:Context3D = Starling.context; if (context == null) throw new MissingContextError(); beforeDraw(context); context.drawTriangles(indexBuffer, firstIndex, numTriangles); afterDraw(context); } /** This method is called by render, directly before * context.drawTriangles. It activates the program and sets up * the context with the following constants and attributes: * *
    *
  • vc0-vc3 — MVP matrix
  • *
  • va0 — vertex position (xy)
  • *
*/ protected function beforeDraw(context:Context3D):void { program.activate(context); vertexFormat.setVertexBufferAttribute(vertexBuffer, 0, "position"); context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix3D, true); } /** This method is called by render, directly after * context.drawTriangles. Resets vertex buffer attributes. */ protected function afterDraw(context:Context3D):void { context.setVertexBufferAt(0, null); } // program management /** Creates the program (a combination of vertex- and fragment-shader) used to render * the effect with the current settings. Override this method in a subclass to create * your shaders. This method will only be called once; the program is automatically stored * in the Painter and re-used by all instances of this effect. * *

The basic implementation always outputs pure white.

*/ protected function createProgram():Program { var vertexShader:String = [ "m44 op, va0, vc0", // 4x4 matrix transform to output clipspace "seq v0, va0, va0" // this is a hack that always produces "1" ].join("\n"); var fragmentShader:String = "mov oc, v0"; // output color: white return Program.fromSource(vertexShader, fragmentShader); } /** Override this method if the effect requires a different program depending on the * current settings. Ideally, you do this by creating a bit mask encoding all the options. * This method is called often, so do not allocate any temporary objects when overriding. * * @default 0 */ protected function get programVariantName():uint { return 0; } /** Returns the base name for the program. * @default the fully qualified class name */ protected function get programBaseName():String { return _programBaseName; } protected function set programBaseName(value:String):void { _programBaseName = value; } /** Returns the full name of the program, which is used to register it at the current * Painter. * *

The default implementation efficiently combines the program's base and variant * names (e.g. LightEffect#42). It shouldn't be necessary to override * this method.

*/ protected function get programName():String { var baseName:String = this.programBaseName; var variantName:uint = this.programVariantName; var nameCache:Dictionary = sProgramNameCache[baseName]; if (nameCache == null) { nameCache = new Dictionary(); sProgramNameCache[baseName] = nameCache; } var name:String = nameCache[variantName]; if (name == null) { if (variantName) name = baseName + "#" + variantName.toString(16); else name = baseName; nameCache[variantName] = name; } return name; } /** Returns the current program, either by creating a new one (via * createProgram) or by getting it from the Painter. * Do not override this method! Instead, implement createProgram. */ protected function get program():Program { var name:String = this.programName; var painter:Painter = Starling.painter; var program:Program = painter.getProgram(name); if (program == null) { program = createProgram(); painter.registerProgram(name, program); } return program; } // properties /** The function that you provide here will be called after a context loss. * Call both "upload..." methods from within the callback to restore any vertex or * index buffers. The callback will be executed with the effect as its sole parameter. */ public function get onRestore():Function { return _onRestore; } public function set onRestore(value:Function):void { _onRestore = value; } /** The data format that this effect requires from the VertexData that it renders: * "position:float2" */ public function get vertexFormat():VertexDataFormat { return VERTEX_FORMAT; } /** The MVP (modelview-projection) matrix transforms vertices into clipspace. */ public function get mvpMatrix3D():Matrix3D { return _mvpMatrix3D; } public function set mvpMatrix3D(value:Matrix3D):void { _mvpMatrix3D.copyFrom(value); } /** The internally used index buffer used on rendering. */ protected function get indexBuffer():IndexBuffer3D { return _indexBuffer; } /** The current size of the index buffer (in number of indices). */ protected function get indexBufferSize():int { return _indexBufferSize; } /** The internally used vertex buffer used on rendering. */ protected function get vertexBuffer():VertexBuffer3D { return _vertexBuffer; } /** The current size of the vertex buffer (in blocks of 32 bits). */ protected function get vertexBufferSize():int { return _vertexBufferSize; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy