PageRenderTime 127ms CodeModel.GetById 33ms app.highlight 81ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/adobe/utils/AGALMiniAssembler.as

https://bitbucket.org/HopeSky/mars_nd2d
ActionScript | 792 lines | 586 code | 81 blank | 125 comment | 90 complexity | 9da226f8ed97059ae9470cf75ece9ff8 MD5 | raw file
  1/*
  2Copyright (c) 2011, Adobe Systems Incorporated
  3All rights reserved.
  4
  5Redistribution and use in source and binary forms, with or without 
  6modification, are permitted provided that the following conditions are
  7met:
  8
  9* Redistributions of source code must retain the above copyright notice, 
 10this list of conditions and the following disclaimer.
 11
 12* Redistributions in binary form must reproduce the above copyright
 13notice, this list of conditions and the following disclaimer in the 
 14documentation and/or other materials provided with the distribution.
 15
 16* Neither the name of Adobe Systems Incorporated nor the names of its 
 17contributors may be used to endorse or promote products derived from 
 18this software without specific prior written permission.
 19
 20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 22THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 23PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 24CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 25EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 26PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 27PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 28LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 29NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 30SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 31*/
 32package com.adobe.utils
 33{
 34	// ===========================================================================
 35	//	Imports
 36	// ---------------------------------------------------------------------------
 37	import flash.display3D.*;
 38	import flash.utils.*;
 39	
 40	// ===========================================================================
 41	//	Class
 42	//  我们可以通过字符串指令来获得一个AGAL二进制流
 43	public class AGALMiniAssembler
 44	{		// ======================================================================
 45		//	Constants
 46		// ----------------------------------------------------------------------				
 47		protected static const REGEXP_OUTER_SPACES:RegExp		= /^\s+|\s+$/g;
 48		
 49		// ======================================================================
 50		//	Properties
 51		// ----------------------------------------------------------------------
 52		// AGAL bytes and error buffer 
 53		private var _agalcode:ByteArray							= null;
 54		private var _error:String								= "";
 55		
 56		private var debugEnabled:Boolean						= false;
 57		
 58		private static var initialized:Boolean					= false;
 59		public var verbose:Boolean								= false;
 60		
 61		// ======================================================================
 62		//	Getters
 63		// ----------------------------------------------------------------------
 64		public function get error():String						{ return _error; }
 65		public function get agalcode():ByteArray				{ return _agalcode; }
 66		
 67		// ======================================================================
 68		//	Constructor
 69		// ----------------------------------------------------------------------
 70		public function AGALMiniAssembler( debugging:Boolean = false ):void
 71		{
 72			debugEnabled = debugging;
 73			if ( !initialized )
 74				init();
 75		}
 76		// ======================================================================
 77		//	Methods
 78		// ----------------------------------------------------------------------
 79		
 80		public function assemble2( ctx3d : Context3D, version:uint, vertexsrc:String, fragmentsrc:String ) : Program3D 
 81		{
 82			var agalvertex : ByteArray = assemble ( VERTEX, vertexsrc, version );
 83			var agalfragment : ByteArray = assemble ( FRAGMENT, fragmentsrc, version );
 84			var prog : Program3D = ctx3d.createProgram(); 
 85			prog.upload(agalvertex,agalfragment);
 86			return prog; 
 87		}
 88		
 89		public function assemble( mode:String, source:String, version:uint=1 ):ByteArray
 90		{
 91			var start:uint = getTimer();
 92			
 93			_agalcode							= new ByteArray();
 94			_error = "";
 95			
 96			var isFrag:Boolean = false;
 97			
 98			if ( mode == FRAGMENT )
 99				isFrag = true;
100			else if ( mode != VERTEX )
101				_error = 'ERROR: mode needs to be "' + FRAGMENT + '" or "' + VERTEX + '" but is "' + mode + '".';
102			
103			agalcode.endian = Endian.LITTLE_ENDIAN;
104			agalcode.writeByte( 0xa0 );				// tag version
105			agalcode.writeUnsignedInt( version );		// AGAL version, big endian, bit pattern will be 0x01000000
106			agalcode.writeByte( 0xa1 );				// tag program id
107			agalcode.writeByte( isFrag ? 1 : 0 );	// vertex or fragment
108			
109			initregmap(version); 
110			
111			var lines:Array = source.replace( /[\f\n\r\v]+/g, "\n" ).split( "\n" );
112			var nest:int = 0;
113			var nops:int = 0;
114			var i:int;
115			var lng:int = lines.length;
116			
117			for ( i = 0; i < lng && _error == ""; i++ )
118			{
119				var line:String = new String( lines[i] );
120				line = line.replace( REGEXP_OUTER_SPACES, "" );
121				
122				// remove comments
123				var startcomment:int = line.search( "//" );
124				if ( startcomment != -1 )
125					line = line.slice( 0, startcomment );
126				
127				// grab options
128				var optsi:int = line.search( /<.*>/g );
129				var opts:Array;
130				if ( optsi != -1 )
131				{
132					opts = line.slice( optsi ).match( /([\w\.\-\+]+)/gi );
133					line = line.slice( 0, optsi );
134				}
135				
136				// find opcode
137				var opCode:Array = line.match( /^\w{3}/ig );
138				if ( !opCode ) 
139				{
140					if ( line.length >= 3 )
141						trace( "warning: bad line "+i+": "+lines[i] );
142					continue;
143				}
144				var opFound:OpCode = OPMAP[ opCode[0] ];
145				
146				// if debug is enabled, output the opcodes
147				if ( debugEnabled )
148					trace( opFound );
149				
150				if ( opFound == null )
151				{
152					if ( line.length >= 3 )
153						trace( "warning: bad line "+i+": "+lines[i] );
154					continue;
155				}
156				
157				line = line.slice( line.search( opFound.name ) + opFound.name.length );
158				
159				if ( ( opFound.flags & OP_VERSION2 ) && version<2 )
160				{
161					_error = "error: opcode requires version 2.";
162					break;					
163				}
164					
165				if ( ( opFound.flags & OP_VERT_ONLY ) && isFrag )
166				{
167					_error = "error: opcode is only allowed in vertex programs.";
168					break;
169				}		
170					
171				if ( ( opFound.flags & OP_FRAG_ONLY ) && !isFrag )
172				{
173					_error = "error: opcode is only allowed in fragment programs.";
174					break;
175				}
176				if ( verbose )
177					trace( "emit opcode=" + opFound );
178				
179				agalcode.writeUnsignedInt( opFound.emitCode );
180				nops++;
181				
182				if ( nops > MAX_OPCODES )
183				{
184					_error = "error: too many opcodes. maximum is "+MAX_OPCODES+".";
185					break;
186				}
187				
188				// get operands, use regexp
189				var regs:Array;
190				
191				// will match both syntax
192				regs = line.match( /vc\[([vof][acostdip]?)(\d*)?(\.[xyzw](\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vof][acostdip]?)(\d*)?(\.[xyzw]{1,4})?/gi );
193				
194				if ( !regs || regs.length != opFound.numRegister )
195				{
196					_error = "error: wrong number of operands. found "+regs.length+" but expected "+opFound.numRegister+".";
197					break;					
198				}
199				
200				var badreg:Boolean	= false;
201				var pad:uint		= 64 + 64 + 32;
202				var regLength:uint	= regs.length;
203				
204				for ( var j:int = 0; j < regLength; j++ )
205				{
206					var isRelative:Boolean = false;
207					var relreg:Array = regs[ j ].match( /\[.*\]/ig );
208					if ( relreg && relreg.length > 0 )
209					{
210						regs[ j ] = regs[ j ].replace( relreg[ 0 ], "0" );
211						
212						if ( verbose )
213							trace( "IS REL" );
214						isRelative = true;
215					}
216					
217					var res:Array = regs[j].match( /^\b[A-Za-z]{1,2}/ig );
218					if ( !res ) 
219					{
220						_error = "error: could not parse operand "+j+" ("+regs[j]+").";
221						badreg = true;
222						break;
223					}
224					var regFound:Register = REGMAP[ res[ 0 ] ];
225					
226					// if debug is enabled, output the registers
227					if ( debugEnabled )
228						trace( regFound );
229					
230					if ( regFound == null )
231					{
232						_error = "error: could not find register name for operand "+j+" ("+regs[j]+").";
233						badreg = true;
234						break;
235					}
236					
237					if ( isFrag )
238					{
239						if ( !( regFound.flags & REG_FRAG ) )
240						{
241							_error = "error: register operand "+j+" ("+regs[j]+") only allowed in vertex programs.";
242							badreg = true;
243							break;
244						}
245						if ( isRelative )
246						{
247							_error = "error: register operand "+j+" ("+regs[j]+") relative adressing not allowed in fragment programs.";
248							badreg = true;
249							break;
250						}			
251					}
252					else
253					{
254						if ( !( regFound.flags & REG_VERT ) )
255						{
256							_error = "error: register operand "+j+" ("+regs[j]+") only allowed in fragment programs.";
257							badreg = true;
258							break;
259						}
260					}
261					
262					regs[j] = regs[j].slice( regs[j].search( regFound.name ) + regFound.name.length );
263					//trace( "REGNUM: " +regs[j] );
264					var idxmatch:Array = isRelative ? relreg[0].match( /\d+/ ) : regs[j].match( /\d+/ );
265					var regidx:uint = 0;
266					
267					if ( idxmatch )
268						regidx = uint( idxmatch[0] );
269					
270					if ( regFound.range < regidx )
271					{
272						_error = "error: register operand "+j+" ("+regs[j]+") index exceeds limit of "+(regFound.range+1)+".";
273						badreg = true;
274						break;
275					}
276					
277					var regmask:uint		= 0;
278					var maskmatch:Array		= regs[j].match( /(\.[xyzw]{1,4})/ );
279					var isDest:Boolean		= ( j == 0 && !( opFound.flags & OP_NO_DEST ) );
280					var isSampler:Boolean	= ( j == 2 && ( opFound.flags & OP_SPECIAL_TEX ) );
281					var reltype:uint		= 0;
282					var relsel:uint			= 0;
283					var reloffset:int		= 0;
284					
285					if ( isDest && isRelative )
286					{
287						_error = "error: relative can not be destination";	
288						badreg = true; 
289						break;								
290					}
291					
292					if ( maskmatch )
293					{
294						regmask = 0;
295						var cv:uint; 
296						var maskLength:uint = maskmatch[0].length;
297						for ( var k:int = 1; k < maskLength; k++ )
298						{
299							cv = maskmatch[0].charCodeAt(k) - "x".charCodeAt(0);
300							if ( cv > 2 )
301								cv = 3;
302							if ( isDest )
303								regmask |= 1 << cv;
304							else
305								regmask |= cv << ( ( k - 1 ) << 1 );
306						}
307						if ( !isDest )
308							for ( ; k <= 4; k++ )
309								regmask |= cv << ( ( k - 1 ) << 1 ); // repeat last								
310					}
311					else
312					{
313						regmask = isDest ? 0xf : 0xe4; // id swizzle or mask						
314					}
315					
316					if ( isRelative )
317					{
318						var relname:Array = relreg[0].match( /[A-Za-z]{1,2}/ig );						
319						var regFoundRel:Register = REGMAP[ relname[0]];						
320						if ( regFoundRel == null )
321						{ 
322							_error = "error: bad index register"; 
323							badreg = true; 
324							break;
325						}
326						reltype = regFoundRel.emitCode;
327						var selmatch:Array = relreg[0].match( /(\.[xyzw]{1,1})/ );						
328						if ( selmatch.length==0 )
329						{
330							_error = "error: bad index register select"; 
331							badreg = true; 
332							break;						
333						}
334						relsel = selmatch[0].charCodeAt(1) - "x".charCodeAt(0);
335						if ( relsel > 2 )
336							relsel = 3; 
337						var relofs:Array = relreg[0].match( /\+\d{1,3}/ig );
338						if ( relofs.length > 0 ) 
339							reloffset = relofs[0]; 						
340						if ( reloffset < 0 || reloffset > 255 )
341						{
342							_error = "error: index offset "+reloffset+" out of bounds. [0..255]"; 
343							badreg = true; 
344							break;							
345						}
346						if ( verbose )
347							trace( "RELATIVE: type="+reltype+"=="+relname[0]+" sel="+relsel+"=="+selmatch[0]+" idx="+regidx+" offset="+reloffset ); 
348					}
349					
350					if ( verbose )
351						trace( "  emit argcode="+regFound+"["+regidx+"]["+regmask+"]" );
352					if ( isDest )
353					{												
354						agalcode.writeShort( regidx );
355						agalcode.writeByte( regmask );
356						agalcode.writeByte( regFound.emitCode );
357						pad -= 32; 
358					} else
359					{
360						if ( isSampler )
361						{
362							if ( verbose )
363								trace( "  emit sampler" );
364							var samplerbits:uint = 5; // type 5 
365							var optsLength:uint = opts == null ? 0 : opts.length;
366							var bias:Number = 0; 
367							for ( k = 0; k<optsLength; k++ )
368							{
369								if ( verbose )
370									trace( "    opt: "+opts[k] );
371								var optfound:Sampler = SAMPLEMAP [opts[k]];
372								if ( optfound == null )
373								{
374									// todo check that it's a number...
375									//trace( "Warning, unknown sampler option: "+opts[k] );
376									bias = Number(opts[k]); 
377									if ( verbose )
378										trace( "    bias: " + bias );																	
379								}
380								else
381								{
382									if ( optfound.flag != SAMPLER_SPECIAL_SHIFT )
383										samplerbits &= ~( 0xf << optfound.flag );										
384									samplerbits |= uint( optfound.mask ) << uint( optfound.flag );
385								}
386							}
387							agalcode.writeShort( regidx );
388							agalcode.writeByte(int(bias*8.0));
389							agalcode.writeByte(0);							
390							agalcode.writeUnsignedInt( samplerbits );
391							
392							if ( verbose )
393								trace( "    bits: " + ( samplerbits - 5 ) );
394							pad -= 64;
395						}
396						else
397						{
398							if ( j == 0 )
399							{
400								agalcode.writeUnsignedInt( 0 );
401								pad -= 32;
402							}
403							agalcode.writeShort( regidx );
404							agalcode.writeByte( reloffset );
405							agalcode.writeByte( regmask );
406							agalcode.writeByte( regFound.emitCode );
407							agalcode.writeByte( reltype );
408							agalcode.writeShort( isRelative ? ( relsel | ( 1 << 15 ) ) : 0 );
409							
410							pad -= 64;
411						}
412					}
413				}
414				
415				// pad unused regs
416				for ( j = 0; j < pad; j += 8 ) 
417					agalcode.writeByte( 0 );
418				
419				if ( badreg )
420					break;
421			}
422			
423			if ( _error != "" )
424			{
425				_error += "\n  at line " + i + " " + lines[i];
426				agalcode.length = 0;
427				trace( _error );
428			}
429			
430			// trace the bytecode bytes if debugging is enabled
431			if ( debugEnabled )
432			{
433				var dbgLine:String = "generated bytecode:";
434				var agalLength:uint = agalcode.length;
435				for ( var index:uint = 0; index < agalLength; index++ )
436				{
437					if ( !( index % 16 ) )
438						dbgLine += "\n";
439					if ( !( index % 4 ) )
440						dbgLine += " ";
441					
442					var byteStr:String = agalcode[ index ].toString( 16 );
443					if ( byteStr.length < 2 )
444						byteStr = "0" + byteStr;
445					
446					dbgLine += byteStr;
447				}
448				trace( dbgLine );
449			}
450			
451			if ( verbose )
452				trace( "AGALMiniAssembler.assemble time: " + ( ( getTimer() - start ) / 1000 ) + "s" );
453			
454			return agalcode;
455		}
456		
457		private function initregmap ( version:uint ) : void {
458			// version changes limits				
459			REGMAP[ VA ]	= new Register( VA,	"vertex attribute",		0x0,	7,						REG_VERT | REG_READ );
460			REGMAP[ VC ]	= new Register( VC,	"vertex constant",		0x1,	version==1?127:250,		REG_VERT | REG_READ );
461			REGMAP[ VT ]	= new Register( VT,	"vertex temporary",		0x2,	version==1?7:27,		REG_VERT | REG_WRITE | REG_READ );
462			REGMAP[ VO ]	= new Register( VO,	"vertex output",		0x3,	0,						REG_VERT | REG_WRITE );
463			REGMAP[ VI ]	= new Register( VI,	"varying",				0x4,	version==1?7:11,		REG_VERT | REG_FRAG | REG_READ | REG_WRITE );			
464			REGMAP[ FC ]	= new Register( FC,	"fragment constant",	0x1,	version==1?27:63,		REG_FRAG | REG_READ );
465			REGMAP[ FT ]	= new Register( FT,	"fragment temporary",	0x2,	version==1?7:27,		REG_FRAG | REG_WRITE | REG_READ );
466			REGMAP[ FS ]	= new Register( FS,	"texture sampler",		0x5,	7,						REG_FRAG | REG_READ );
467			REGMAP[ FO ]	= new Register( FO,	"fragment output",		0x3,	version==1?0:3,			REG_FRAG | REG_WRITE );				
468			REGMAP[ FD ]	= new Register( FD,	"fragment depth output",0x6,	version==1?-1:0,		REG_FRAG | REG_WRITE );
469			
470			// aliases
471			REGMAP[ "op" ]	= REGMAP[ VO ];
472			REGMAP[ "i" ]	= REGMAP[ VI ];
473			REGMAP[ "v" ]	= REGMAP[ VI ];
474			REGMAP[ "oc" ]	= REGMAP[ FO ];					
475			REGMAP[ "fi" ]	= REGMAP[ VI ]; 
476		}
477		
478		static private function init():void
479		{
480			initialized = true;
481			
482			// Fill the dictionaries with opcodes and registers
483			OPMAP[ MOV ] = new OpCode( MOV, 2, 0x00, 0 );
484			OPMAP[ ADD ] = new OpCode( ADD, 3, 0x01, 0 );
485			OPMAP[ SUB ] = new OpCode( SUB, 3, 0x02, 0 );
486			OPMAP[ MUL ] = new OpCode( MUL, 3, 0x03, 0 );
487			OPMAP[ DIV ] = new OpCode( DIV, 3, 0x04, 0 );
488			OPMAP[ RCP ] = new OpCode( RCP, 2, 0x05, 0 );					
489			OPMAP[ MIN ] = new OpCode( MIN, 3, 0x06, 0 );
490			OPMAP[ MAX ] = new OpCode( MAX, 3, 0x07, 0 );
491			OPMAP[ FRC ] = new OpCode( FRC, 2, 0x08, 0 );			
492			OPMAP[ SQT ] = new OpCode( SQT, 2, 0x09, 0 );
493			OPMAP[ RSQ ] = new OpCode( RSQ, 2, 0x0a, 0 );
494			OPMAP[ POW ] = new OpCode( POW, 3, 0x0b, 0 );
495			OPMAP[ LOG ] = new OpCode( LOG, 2, 0x0c, 0 );
496			OPMAP[ EXP ] = new OpCode( EXP, 2, 0x0d, 0 );
497			OPMAP[ NRM ] = new OpCode( NRM, 2, 0x0e, 0 );
498			OPMAP[ SIN ] = new OpCode( SIN, 2, 0x0f, 0 );
499			OPMAP[ COS ] = new OpCode( COS, 2, 0x10, 0 );
500			OPMAP[ CRS ] = new OpCode( CRS, 3, 0x11, 0 );
501			OPMAP[ DP3 ] = new OpCode( DP3, 3, 0x12, 0 );
502			OPMAP[ DP4 ] = new OpCode( DP4, 3, 0x13, 0 );					
503			OPMAP[ ABS ] = new OpCode( ABS, 2, 0x14, 0 );
504			OPMAP[ NEG ] = new OpCode( NEG, 2, 0x15, 0 );
505			OPMAP[ SAT ] = new OpCode( SAT, 2, 0x16, 0 );
506			OPMAP[ M33 ] = new OpCode( M33, 3, 0x17, OP_SPECIAL_MATRIX );
507			OPMAP[ M44 ] = new OpCode( M44, 3, 0x18, OP_SPECIAL_MATRIX );
508			OPMAP[ M34 ] = new OpCode( M34, 3, 0x19, OP_SPECIAL_MATRIX );		
509			OPMAP[ DDX ] = new OpCode( DDX, 2, 0x1a, OP_VERSION2 | OP_FRAG_ONLY );
510			OPMAP[ DDY ] = new OpCode( DDY, 2, 0x1b, OP_VERSION2 | OP_FRAG_ONLY );			
511			OPMAP[ IFE ] = new OpCode( IFE, 2, 0x1c, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
512			OPMAP[ INE ] = new OpCode( INE, 2, 0x1d, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
513			OPMAP[ IFG ] = new OpCode( IFG, 2, 0x1e, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );			
514			OPMAP[ IFL ] = new OpCode( IFL, 2, 0x1f, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
515			OPMAP[ ELS ] = new OpCode( ELS, 0, 0x20, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_DECNEST | OP_SCALAR );
516			OPMAP[ EIF ] = new OpCode( EIF, 0, 0x21, OP_NO_DEST | OP_VERSION2 | OP_DECNEST | OP_SCALAR );
517			// space			
518			OPMAP[ TED ] = new OpCode( TED, 3, 0x26, OP_FRAG_ONLY | OP_SPECIAL_TEX | OP_VERSION2);			
519			OPMAP[ KIL ] = new OpCode( KIL, 1, 0x27, OP_NO_DEST | OP_FRAG_ONLY );
520			OPMAP[ TEX ] = new OpCode( TEX, 3, 0x28, OP_FRAG_ONLY | OP_SPECIAL_TEX );
521			OPMAP[ SGE ] = new OpCode( SGE, 3, 0x29, 0 );
522			OPMAP[ SLT ] = new OpCode( SLT, 3, 0x2a, 0 );
523			OPMAP[ SGN ] = new OpCode( SGN, 2, 0x2b, 0 );
524			OPMAP[ SEQ ] = new OpCode( SEQ, 3, 0x2c, 0 );
525			OPMAP[ SNE ] = new OpCode( SNE, 3, 0x2d, 0 );			
526		
527			
528			SAMPLEMAP[ RGBA ]		= new Sampler( RGBA,		SAMPLER_TYPE_SHIFT,			0 );
529			SAMPLEMAP[ DXT1 ]		= new Sampler( DXT1,		SAMPLER_TYPE_SHIFT,			1 );
530			SAMPLEMAP[ DXT5 ]		= new Sampler( DXT5,		SAMPLER_TYPE_SHIFT,			2 );
531			SAMPLEMAP[ VIDEO ]		= new Sampler( VIDEO,		SAMPLER_TYPE_SHIFT,			3 );
532			SAMPLEMAP[ D2 ]			= new Sampler( D2,			SAMPLER_DIM_SHIFT,			0 );
533			SAMPLEMAP[ D3 ]			= new Sampler( D3,			SAMPLER_DIM_SHIFT,			2 );
534			SAMPLEMAP[ CUBE ]		= new Sampler( CUBE,		SAMPLER_DIM_SHIFT,			1 );
535			SAMPLEMAP[ MIPNEAREST ]	= new Sampler( MIPNEAREST,	SAMPLER_MIPMAP_SHIFT,		1 );
536			SAMPLEMAP[ MIPLINEAR ]	= new Sampler( MIPLINEAR,	SAMPLER_MIPMAP_SHIFT,		2 );
537			SAMPLEMAP[ MIPNONE ]	= new Sampler( MIPNONE,		SAMPLER_MIPMAP_SHIFT,		0 );
538			SAMPLEMAP[ NOMIP ]		= new Sampler( NOMIP,		SAMPLER_MIPMAP_SHIFT,		0 );
539			SAMPLEMAP[ NEAREST ]	= new Sampler( NEAREST,		SAMPLER_FILTER_SHIFT,		0 );
540			SAMPLEMAP[ LINEAR ]		= new Sampler( LINEAR,		SAMPLER_FILTER_SHIFT,		1 );
541			SAMPLEMAP[ CENTROID ]	= new Sampler( CENTROID,	SAMPLER_SPECIAL_SHIFT,		1 << 0 );
542			SAMPLEMAP[ SINGLE ]		= new Sampler( SINGLE,		SAMPLER_SPECIAL_SHIFT,		1 << 1 );
543			SAMPLEMAP[ DEPTH ]		= new Sampler( DEPTH,		SAMPLER_SPECIAL_SHIFT,		1 << 2 );
544			SAMPLEMAP[ REPEAT ]		= new Sampler( REPEAT,		SAMPLER_REPEAT_SHIFT,		1 );
545			SAMPLEMAP[ WRAP ]		= new Sampler( WRAP,		SAMPLER_REPEAT_SHIFT,		1 );
546			SAMPLEMAP[ CLAMP ]		= new Sampler( CLAMP,		SAMPLER_REPEAT_SHIFT,		0 );
547		}
548		
549		// ======================================================================
550		//	Constants
551		// ----------------------------------------------------------------------
552		private static const OPMAP:Dictionary					= new Dictionary();
553		private static const REGMAP:Dictionary					= new Dictionary();
554		private static const SAMPLEMAP:Dictionary				= new Dictionary();
555		
556		private static const MAX_NESTING:int					= 4;
557		private static const MAX_OPCODES:int					= 256;
558		
559		private static const FRAGMENT:String					= "fragment";
560		private static const VERTEX:String						= "vertex";
561		
562		// masks and shifts
563		private static const SAMPLER_TYPE_SHIFT:uint			= 8;
564		private static const SAMPLER_DIM_SHIFT:uint				= 12;
565		private static const SAMPLER_SPECIAL_SHIFT:uint			= 16;
566		private static const SAMPLER_REPEAT_SHIFT:uint			= 20;
567		private static const SAMPLER_MIPMAP_SHIFT:uint			= 24;
568		private static const SAMPLER_FILTER_SHIFT:uint			= 28;
569		
570		// regmap flags
571		private static const REG_WRITE:uint						= 0x1;
572		private static const REG_READ:uint						= 0x2;
573		private static const REG_FRAG:uint						= 0x20;
574		private static const REG_VERT:uint						= 0x40;
575		
576		// opmap flags
577		private static const OP_SCALAR:uint						= 0x1;
578		private static const OP_SPECIAL_TEX:uint				= 0x8;
579		private static const OP_SPECIAL_MATRIX:uint				= 0x10;
580		private static const OP_FRAG_ONLY:uint					= 0x20;
581		private static const OP_VERT_ONLY:uint					= 0x40;
582		private static const OP_NO_DEST:uint					= 0x80;
583		private static const OP_VERSION2:uint 					= 0x100;		
584		private static const OP_INCNEST:uint 					= 0x200;
585		private static const OP_DECNEST:uint					= 0x400;
586		
587		// opcodes
588		private static const MOV:String							= "mov";
589		private static const ADD:String							= "add";
590		private static const SUB:String							= "sub";
591		private static const MUL:String							= "mul";
592		private static const DIV:String							= "div";
593		private static const RCP:String							= "rcp";
594		private static const MIN:String							= "min";
595		private static const MAX:String							= "max";
596		private static const FRC:String							= "frc";
597		private static const SQT:String							= "sqt";
598		private static const RSQ:String							= "rsq";
599		private static const POW:String							= "pow";
600		private static const LOG:String							= "log";
601		private static const EXP:String							= "exp";
602		private static const NRM:String							= "nrm";
603		private static const SIN:String							= "sin";
604		private static const COS:String							= "cos";
605		private static const CRS:String							= "crs";
606		private static const DP3:String							= "dp3";
607		private static const DP4:String							= "dp4";
608		private static const ABS:String							= "abs";
609		private static const NEG:String							= "neg";
610		private static const SAT:String							= "sat";
611		private static const M33:String							= "m33";
612		private static const M44:String							= "m44";
613		private static const M34:String							= "m34";
614		private static const DDX:String							= "ddx";
615		private static const DDY:String							= "ddy";		
616		private static const IFE:String							= "ife";
617		private static const INE:String							= "ine";
618		private static const IFG:String							= "ifg";
619		private static const IFL:String							= "ifl";
620		private static const ELS:String							= "els";
621		private static const EIF:String							= "eif";
622		private static const TED:String							= "ted";
623		private static const KIL:String							= "kil";
624		private static const TEX:String							= "tex";
625		private static const SGE:String							= "sge";
626		private static const SLT:String							= "slt";
627		private static const SGN:String							= "sgn";
628		private static const SEQ:String							= "seq";
629		private static const SNE:String							= "sne";		
630		
631		// registers
632		private static const VA:String							= "va";
633		private static const VC:String							= "vc";
634		private static const VT:String							= "vt";
635		private static const VO:String							= "vo";
636		private static const VI:String							= "vi";
637		private static const FC:String							= "fc";
638		private static const FT:String							= "ft";
639		private static const FS:String							= "fs";
640		private static const FO:String							= "fo";			
641		private static const FD:String							= "fd"; 
642		
643		// samplers
644		private static const D2:String							= "2d";
645		private static const D3:String							= "3d";
646		private static const CUBE:String						= "cube";
647		private static const MIPNEAREST:String					= "mipnearest";
648		private static const MIPLINEAR:String					= "miplinear";
649		private static const MIPNONE:String						= "mipnone";
650		private static const NOMIP:String						= "nomip";
651		private static const NEAREST:String						= "nearest";
652		private static const LINEAR:String						= "linear";
653		private static const CENTROID:String					= "centroid";
654		private static const SINGLE:String						= "single";
655		private static const DEPTH:String						= "depth";
656		private static const REPEAT:String						= "repeat";
657		private static const WRAP:String						= "wrap";
658		private static const CLAMP:String						= "clamp";
659		private static const RGBA:String						= "rgba";
660		private static const DXT1:String						= "dxt1";
661		private static const DXT5:String						= "dxt5";
662		private static const VIDEO:String						= "video";
663	}
664}
665
666// ================================================================================
667//	Helper Classes
668// --------------------------------------------------------------------------------
669{
670	// ===========================================================================
671	//	Class
672	// ---------------------------------------------------------------------------
673	class OpCode
674	{		
675		// ======================================================================
676		//	Properties
677		// ----------------------------------------------------------------------
678		private var _emitCode:uint;
679		private var _flags:uint;
680		private var _name:String;
681		private var _numRegister:uint;
682		
683		// ======================================================================
684		//	Getters
685		// ----------------------------------------------------------------------
686		public function get emitCode():uint		{ return _emitCode; }
687		public function get flags():uint		{ return _flags; }
688		public function get name():String		{ return _name; }
689		public function get numRegister():uint	{ return _numRegister; }
690		
691		// ======================================================================
692		//	Constructor
693		// ----------------------------------------------------------------------
694		public function OpCode( name:String, numRegister:uint, emitCode:uint, flags:uint)
695		{
696			_name = name;
697			_numRegister = numRegister;
698			_emitCode = emitCode;
699			_flags = flags;
700		}		
701		
702		// ======================================================================
703		//	Methods
704		// ----------------------------------------------------------------------
705		public function toString():String
706		{
707			return "[OpCode name=\""+_name+"\", numRegister="+_numRegister+", emitCode="+_emitCode+", flags="+_flags+"]";
708		}
709	}
710	
711	// ===========================================================================
712	//	Class
713	// ---------------------------------------------------------------------------
714	class Register
715	{
716		// ======================================================================
717		//	Properties
718		// ----------------------------------------------------------------------
719		private var _emitCode:uint;
720		private var _name:String;
721		private var _longName:String;
722		private var _flags:uint;
723		private var _range:uint;
724		
725		// ======================================================================
726		//	Getters
727		// ----------------------------------------------------------------------
728		public function get emitCode():uint		{ return _emitCode; }
729		public function get longName():String	{ return _longName; }
730		public function get name():String		{ return _name; }
731		public function get flags():uint		{ return _flags; }
732		public function get range():uint		{ return _range; }
733		
734		// ======================================================================
735		//	Constructor
736		// ----------------------------------------------------------------------
737		public function Register( name:String, longName:String, emitCode:uint, range:uint, flags:uint)
738		{
739			_name = name;
740			_longName = longName;
741			_emitCode = emitCode;
742			_range = range;
743			_flags = flags;
744		}
745		
746		// ======================================================================
747		//	Methods
748		// ----------------------------------------------------------------------
749		public function toString():String
750		{
751			return "[Register name=\""+_name+"\", longName=\""+_longName+"\", emitCode="+_emitCode+", range="+_range+", flags="+ _flags+"]";
752		}
753	}
754	
755	// ===========================================================================
756	//	Class
757	// ---------------------------------------------------------------------------
758	class Sampler
759	{
760		// ======================================================================
761		//	Properties
762		// ----------------------------------------------------------------------
763		private var _flag:uint;
764		private var _mask:uint;
765		private var _name:String;
766		
767		// ======================================================================
768		//	Getters
769		// ----------------------------------------------------------------------
770		public function get flag():uint		{ return _flag; }
771		public function get mask():uint		{ return _mask; }
772		public function get name():String	{ return _name; }
773		
774		// ======================================================================
775		//	Constructor
776		// ----------------------------------------------------------------------
777		public function Sampler( name:String, flag:uint, mask:uint )
778		{
779			_name = name;
780			_flag = flag;
781			_mask = mask;
782		}
783		
784		// ======================================================================
785		//	Methods
786		// ----------------------------------------------------------------------
787		public function toString():String
788		{
789			return "[Sampler name=\""+_name+"\", flag=\""+_flag+"\", mask="+mask+"]";
790		}
791	}
792}