Stage3D Tutorial 3

by WLAD
http://blog.norbz.net/2012/01/stage3d-agal-from-scratch-part-iii-hello-triangle/
♥0 | Line 151 | Modified 2016-07-15 18:27:44 | MIT License
play

ActionScript3 source code

/**
 * Copyright WLAD ( http://wonderfl.net/user/WLAD )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gBJo
 */

/// @mxmlc -swf-version 20
package 
{
	import com.adobe.utils.AGALMiniAssembler;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.utils.ByteArray;
	
	[SWF(width='465', height='465')]
	public class Stage3D_Tutorial_3_gBJo extends Sprite
	{
		public function Stage3D_Tutorial_3_gBJo()
		{
			var S:StageUtil = new StageUtil( stage );
			
			var G:Graphics = this.graphics;
			var B:BitmapData = new BitmapData( S.W, S.H, true, 0 );
			
			// wait for Stage3D to provide us a Context3D
			// first param [true] is for error reporting
			// By enabling the Error reporting, you can get some valuable 
			// information about errors in your shaders
			// But it also dramatically slows down your program.
			S.onContext3D( true, function():void {
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------


////////////////////////////////////////////////
// ### [1]: Allocation - program compilation.
////////////////////////////////////////////////

// CREATE BUFFERS //

// How much Vertex it will have : 3
// How much information each Vertex have : x,y,z,r,g,b = 6
var vertexBuffer:VertexBuffer3D = S.Context.createVertexBuffer( 3, 6 );
// The index buffer needs to know how many instruction he will have. Here 3.
var indexBuffer:IndexBuffer3D = S.Context.createIndexBuffer( 3 );

// CREATE SHADER PROGRAM // 

// When you call the createProgram method you are actually allocating 
// some V-Ram space for your shader program.
var program:Program3D = S.Context.createProgram();

// Create an AGALMiniAssembler //

// The MiniAssembler is an Adobe tool that uses a simple
// Assembly-like language to write and compile your shader into bytecode
var assembler:AGALMiniAssembler = new AGALMiniAssembler();

// VERTEX SHADER //

var code:String = "";
// Move the Vertex Attribute 0 (va0), which is our Vertex 
// Coordinate, to the Output Point (op)
code += "mov op, va0" + "\n"; 
// Move the Vertex Attribute 1 (va1), which is our Vertex 
// Color, to the variable register (v0)
// Variable register are memory space shared between your 
// Vertex Shader and your Fragment Shader
code += "mov v0, va1" + "\n"; 

// COMPILE //

// Compile our AGAL Code into ByteCode using the MiniAssembler 
var vertexShader:ByteArray = 
assembler.assemble(Context3DProgramType.VERTEX, code);

// Move the Variable register 0 (v0) where we copied our 
// Vertex Color, to the output color (oc)
code = "mov oc, v0\n"; 

// Compile our AGAL Code into Bytecode using the MiniAssembler
var fragmentShader:ByteArray = 
assembler.assemble(Context3DProgramType.FRAGMENT, code);

///////////////////////////////////////////////
// ### [2]: Upload program and buffers data.
///////////////////////////////////////////////

// UPLOAD TO GPU PROGRAM // 

// Upload the combined program to the video Ram
program.upload(vertexShader, fragmentShader); 

// Upload some data to the vertex and index buffers
var vertexData:Vector.<Number>=Vector.<Number>([
	-0.3, -0.3, +0.0, +1.0, +0.0, +0.0, 	// 1st vertex x,y,z,r,g,b 
	+0.0, +0.3, +0.0, +0.0, +1.0, +0.0, 	// 2nd vertex x,y,z,r,g,b 
	+0.3, -0.3, +0.0, +0.0, +0.0, +1.0		// 3rd vertex x,y,z,r,g,b
]);	
vertexBuffer.uploadFromVector(vertexData, 0, 3);
indexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2]), 0, 3);

//////////////////////////////////////////////////////////
// ### [3]: Split chunk of data and set active program.
//////////////////////////////////////////////////////////

// Define how each Chunck of Data should be split and upload 
// to fast access register for our AGAL program

// So here, basically, your telling your GPU that for each 
// Vertex with a vertex being x,y,y,r,g,b 
// you will copy in register "0", from the buffer "vertexBuffer, 
// starting from the postion "0" the FLOAT_3 next number
S.Context.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); 
// register "0" now contains x,y,z

// Here, you will copy in register "1" from "vertexBuffer", 
// starting from index "3", the next FLOAT_3 numbers
S.Context.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3); 
// register 1 now contains r,g,b

// Define the active program to run on our GPU
// Set our program as the current active one
S.Context.setProgram(program);

//////////////////////////////////////////////////////////
// ### [4]: Start the rendering loop.
//////////////////////////////////////////////////////////

//Called each frame, Render the scene
S.on('enterFrame', function():void 
{
	// Clear the backbuffer by filling it with the given color
	S.Context.clear(1, 1, 1, 1); 
	// Draw the triangle according to the indexBuffer instructions into the backbuffer
	S.Context.drawTriangles(indexBuffer); 
	// TEMP ( take screen shot )
	if ( takescreenshot ) 
	{
		S.Context.drawToBitmapData( B );
		takescreenshot = false;
		readyscreenshot = true;
	}
	// render the backbuffer on screen.
	S.Context.present(); 
});
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
			});
			
			var takescreenshot:Boolean = false;
			var readyscreenshot:Boolean = false;
			
			S.on('click', function():void {
				if ( ! readyscreenshot ) return;
				G.clear();
				G.beginBitmapFill( B );
				G.drawRect( 0, 0, S.W, S.H );
				G.endFill();
			});
			
			S.on('rightMouseDown', function():void {
				G.clear();
				takescreenshot = true;
			} );
			S.on('doubleClick', function():void {
				
				S.toogleFullScreen();
			});
			
		} // end constractor 
	} // end class 
} // end package 

import flash.display.Stage;
import flash.display3D.Context3D;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFormat;

class StageUtil
{
	/// Context3D
	public var Context:Context3D = null;
	
	// 
	public function onContext3D( errorReporting:Boolean = false, callBack:Function = null ):void
	{
		if ( callBack == null ) return;
		if( errorReporting ) 
		stage.stage3Ds[0].addEventListener('error', function( e:* ):void {
			text( "Context3D Error", e.text );
		});
		stage.stage3Ds[0].addEventListener('context3DCreate', function( e:* ):void {
			Context = stage.stage3Ds[0].context3D;
			Context.enableErrorChecking = errorReporting;
			// Configure the back buffer, in width and height. You can also specify the antialiasing
			// The backbuffer is the memory space where your final image is rendered.
			Context.configureBackBuffer( W, H, 4, true );
			callBack();
			text( "Context3D Created " + Context.driverInfo  );
		});stage.stage3Ds[0].requestContext3D();
	}
	
	
	
	/// stage width
	public var W:int;
	/// stage height 
	public var H:int;
	/// Array of pressed keys 
	public var K:Vector.<Boolean>;
	
	private var stage:Stage;
	public function StageUtil( stage:Stage ):void
	{
		this.stage = stage;
		
		stage.color = 0xFFFFFF;
		
		W = stage.stageWidth;
		H = stage.stageHeight;
			
		stage.doubleClickEnabled = true;
		
		// Keyboard control 
		K = new Vector.<Boolean>();
		for (var k:int = 0; k < 2000; k++) K.push( false );
		var input:Function = function( e:* ):void 
		{K[ e.keyCode ] = e.type == "keyDown";};
		stage.addEventListener('keyDown', input );
		stage.addEventListener('keyUp', input );
	}
	
	public function toogleFullScreen():void
	{
		if ( stage.displayState == 'normal' ) 
		{
			stage.fullScreenSourceRect = new Rectangle( 0, 0, W, H );
			stage.displayState = 'fullScreen';
		}
		else stage.displayState = 'normal';
	}
	
	public function on( event:String, callBack:Function, once:Boolean = false ):void
	{
		var capture:Function = function(e:*):void {
			if ( once ) stage.removeEventListener( event, capture );
			callBack();
		};
		stage.addEventListener( event, capture );
	}
	
	private var label:TextField;
	public function text( ...arguments ):void
	{
		if ( label == null )
		{
			label = new TextField();
			label.x = 5;
			label.autoSize = 'left'; 
			label.mouseEnabled = false;
			label.alpha = 0.5;
			label.defaultTextFormat = new TextFormat("Arial", 12, 0x000000 );
			stage.addChild( label );
		}
		label.appendText( arguments.join("\n") + "\n" );
		label.y = H - label.height - 5;
	}
}