Skip to content

Instantly share code, notes, and snippets.

@liekkas
Forked from PrimaryFeather/Polygon.as
Created April 21, 2012 10:04
Show Gist options
  • Save liekkas/2436304 to your computer and use it in GitHub Desktop.
Save liekkas/2436304 to your computer and use it in GitHub Desktop.
A custom display object for Starling, rendering a regular n-sided polygon.
package utils
{
import com.adobe.utils.AGALMiniAssembler;
import flash.display3D.*;
import flash.geom.*;
import starling.core.RenderSupport;
import starling.core.Starling;
import starling.display.DisplayObject;
import starling.errors.MissingContextError;
import starling.events.Event;
import starling.utils.VertexData;
/** This custom display objects renders a regular, n-sided polygon. */
public class Polygon extends DisplayObject
{
private static var PROGRAM_NAME:String = "polygon";
// custom members
private var mRadius:Number;
private var mNumEdges:int;
private var mColor:uint;
// vertex data
private var mVertexData:VertexData;
private var mVertexBuffer:VertexBuffer3D;
// index data
private var mIndexData:Vector.<uint>;
private var mIndexBuffer:IndexBuffer3D;
// helper objects (to avoid temporary objects)
private static var sHelperMatrix:Matrix = new Matrix();
private static var sRenderAlpha:Vector.<Number> = new <Number>[1.0, 1.0, 1.0, 1.0];
/** Creates a regular polygon with the specified redius, number of edges, and color. */
public function Polygon(radius:Number, numEdges:int=6, color:uint=0xffffff)
{
if (numEdges < 3) throw new ArgumentError("Invalid number of edges");
mRadius = radius;
mNumEdges = numEdges;
mColor = color;
// setup vertex data and prepare shaders
setupVertices();
createBuffers();
registerPrograms();
// handle lost context
Starling.current.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
}
/** Disposes all resources of the display object. */
public override function dispose():void
{
Starling.current.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
if (mVertexBuffer) mVertexBuffer.dispose();
if (mIndexBuffer) mIndexBuffer.dispose();
super.dispose();
}
private function onContextCreated(event:Event):void
{
// the old context was lost, so we create new buffers and shaders.
createBuffers();
registerPrograms();
}
/** Returns a rectangle that completely encloses the object as it appears in another
* coordinate system. */
public override function getBounds(targetSpace:DisplayObject, resultRect:Rectangle=null):Rectangle
{
if (resultRect == null) resultRect = new Rectangle();
var transformationMatrix:Matrix = targetSpace == this ?
null : getTransformationMatrix(targetSpace, sHelperMatrix);
return mVertexData.getBounds(transformationMatrix, 0, -1, resultRect);
}
/** Creates the required vertex- and index data and uploads it to the GPU. */
private function setupVertices():void
{
var i:int;
// create vertices
mVertexData = new VertexData(mNumEdges+1);
mVertexData.setUniformColor(mColor);
for (i=0; i<mNumEdges; ++i)
{
var edge:Point = Point.polar(mRadius, i*2*Math.PI / mNumEdges);
mVertexData.setPosition(i, edge.x, edge.y);
}
mVertexData.setPosition(mNumEdges, 0.0, 0.0); // center vertex
// create indices that span up the triangles
mIndexData = new <uint>[];
for (i=0; i<mNumEdges; ++i)
mIndexData.push(mNumEdges, i, (i+1)%mNumEdges);
}
/** Creates new vertex- and index-buffers and uploads our vertex- and index-data to those
* buffers. */
private function createBuffers():void
{
var context:Context3D = Starling.context;
if (context == null) throw new MissingContextError();
if (mVertexBuffer) mVertexBuffer.dispose();
if (mIndexBuffer) mIndexBuffer.dispose();
mVertexBuffer = context.createVertexBuffer(mVertexData.numVertices, VertexData.ELEMENTS_PER_VERTEX);
mVertexBuffer.uploadFromVector(mVertexData.rawData, 0, mVertexData.numVertices);
mIndexBuffer = context.createIndexBuffer(mIndexData.length);
mIndexBuffer.uploadFromVector(mIndexData, 0, mIndexData.length);
}
/** Renders the object with the help of a 'support' object and with the accumulated alpha
* of its parent object. */
public override function render(support:RenderSupport, alpha:Number):void
{
// always call this method when you write custom rendering code!
// it causes all previously batched quads/images to render.
support.finishQuadBatch();
sRenderAlpha[0] = sRenderAlpha[1] = sRenderAlpha[2] = 1.0;
sRenderAlpha[3] = alpha * this.alpha;
var context:Context3D = Starling.context;
if (context == null) throw new MissingContextError();
// apply the current blendmode
support.applyBlendMode(false);
// activate program (shader) and set the required buffers / constants
context.setProgram(Starling.current.getProgram(PROGRAM_NAME));
context.setVertexBufferAt(0, mVertexBuffer, VertexData.POSITION_OFFSET, Context3DVertexBufferFormat.FLOAT_3);
context.setVertexBufferAt(1, mVertexBuffer, VertexData.COLOR_OFFSET, Context3DVertexBufferFormat.FLOAT_4);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, support.mvpMatrix, true);
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, sRenderAlpha, 1);
// finally: draw the object!
context.drawTriangles(mIndexBuffer, 0, mNumEdges);
// reset buffers
context.setVertexBufferAt(0, null);
context.setVertexBufferAt(1, null);
}
/** Creates vertex and fragment programs from assembly. */
private static function registerPrograms():void
{
var target:Starling = Starling.current;
if (target.hasProgram(PROGRAM_NAME)) return; // already registered
var vertexProgramCode:String =
"m44 op, va0, vc0 \n" + // 4x4 matrix transform to output space
"mov v0, va1 \n"; // pass color to fragment program
var fragmentProgramCode:String =
"mul oc, v0, fc0"; // multiply color with alpha
var vertexProgramAssembler:AGALMiniAssembler = new AGALMiniAssembler();
vertexProgramAssembler.assemble(Context3DProgramType.VERTEX, vertexProgramCode);
var fragmentProgramAssembler:AGALMiniAssembler = new AGALMiniAssembler();
fragmentProgramAssembler.assemble(Context3DProgramType.FRAGMENT, fragmentProgramCode);
target.registerProgram(PROGRAM_NAME, vertexProgramAssembler.agalcode,
fragmentProgramAssembler.agalcode);
}
/** The radius of the polygon in points. */
public function get radius():Number { return mRadius; }
public function set radius(value:Number):void { mRadius = value; setupVertices(); }
/** The number of edges of the regular polygon. */
public function get numEdges():int { return mNumEdges; }
public function set numEdges(value:int):void { mNumEdges = value; setupVertices(); }
/** The color of the regular polygon. */
public function get color():uint { return mColor; }
public function set color(value:uint):void { mColor = value; setupVertices(); }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment