PageRenderTime 273ms CodeModel.GetById 33ms app.highlight 185ms RepoModel.GetById 16ms app.codeStats 1ms

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

http://github.com/away3d/away3d-core-fp11
ActionScript | 793 lines | 586 code | 81 blank | 126 comment | 90 complexity | fa4f12ea323b1f15c5d031db2d88f4ed 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	// ---------------------------------------------------------------------------
 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, ignorelimits:Boolean=false ):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, ignorelimits); 
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, ignorelimits:Boolean ) : void {
458			// version changes limits				
459			REGMAP[ VA ]	= new Register( VA,	"vertex attribute",		0x0,	ignorelimits?1024:7,						REG_VERT | REG_READ );
460			REGMAP[ VC ]	= new Register( VC,	"vertex constant",		0x1,	ignorelimits?1024:(version==1?127:250),		REG_VERT | REG_READ );
461			REGMAP[ VT ]	= new Register( VT,	"vertex temporary",		0x2,	ignorelimits?1024:(version==1?7:27),		REG_VERT | REG_WRITE | REG_READ );
462			REGMAP[ VO ]	= new Register( VO,	"vertex output",		0x3,	ignorelimits?1024:0,						REG_VERT | REG_WRITE );
463			REGMAP[ VI ]	= new Register( VI,	"varying",				0x4,	ignorelimits?1024:(version==1?7:11),		REG_VERT | REG_FRAG | REG_READ | REG_WRITE );			
464			REGMAP[ FC ]	= new Register( FC,	"fragment constant",	0x1,	ignorelimits?1024:(version==1?27:63),		REG_FRAG | REG_READ );
465			REGMAP[ FT ]	= new Register( FT,	"fragment temporary",	0x2,	ignorelimits?1024:(version==1?7:27),		REG_FRAG | REG_WRITE | REG_READ );
466			REGMAP[ FS ]	= new Register( FS,	"texture sampler",		0x5,	ignorelimits?1024:7,						REG_FRAG | REG_READ );
467			REGMAP[ FO ]	= new Register( FO,	"fragment output",		0x3,	ignorelimits?1024:(version==1?0:3),			REG_FRAG | REG_WRITE );				
468			REGMAP[ FD ]	= new Register( FD,	"fragment depth output",0x6,	ignorelimits?1024:(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[ "od" ]	= REGMAP[ FD ];					
476			REGMAP[ "fi" ]	= REGMAP[ VI ]; 
477		}
478		
479		static private function init():void
480		{
481			initialized = true;
482			
483			// Fill the dictionaries with opcodes and registers
484			OPMAP[ MOV ] = new OpCode( MOV, 2, 0x00, 0 );
485			OPMAP[ ADD ] = new OpCode( ADD, 3, 0x01, 0 );
486			OPMAP[ SUB ] = new OpCode( SUB, 3, 0x02, 0 );
487			OPMAP[ MUL ] = new OpCode( MUL, 3, 0x03, 0 );
488			OPMAP[ DIV ] = new OpCode( DIV, 3, 0x04, 0 );
489			OPMAP[ RCP ] = new OpCode( RCP, 2, 0x05, 0 );					
490			OPMAP[ MIN ] = new OpCode( MIN, 3, 0x06, 0 );
491			OPMAP[ MAX ] = new OpCode( MAX, 3, 0x07, 0 );
492			OPMAP[ FRC ] = new OpCode( FRC, 2, 0x08, 0 );			
493			OPMAP[ SQT ] = new OpCode( SQT, 2, 0x09, 0 );
494			OPMAP[ RSQ ] = new OpCode( RSQ, 2, 0x0a, 0 );
495			OPMAP[ POW ] = new OpCode( POW, 3, 0x0b, 0 );
496			OPMAP[ LOG ] = new OpCode( LOG, 2, 0x0c, 0 );
497			OPMAP[ EXP ] = new OpCode( EXP, 2, 0x0d, 0 );
498			OPMAP[ NRM ] = new OpCode( NRM, 2, 0x0e, 0 );
499			OPMAP[ SIN ] = new OpCode( SIN, 2, 0x0f, 0 );
500			OPMAP[ COS ] = new OpCode( COS, 2, 0x10, 0 );
501			OPMAP[ CRS ] = new OpCode( CRS, 3, 0x11, 0 );
502			OPMAP[ DP3 ] = new OpCode( DP3, 3, 0x12, 0 );
503			OPMAP[ DP4 ] = new OpCode( DP4, 3, 0x13, 0 );					
504			OPMAP[ ABS ] = new OpCode( ABS, 2, 0x14, 0 );
505			OPMAP[ NEG ] = new OpCode( NEG, 2, 0x15, 0 );
506			OPMAP[ SAT ] = new OpCode( SAT, 2, 0x16, 0 );
507			OPMAP[ M33 ] = new OpCode( M33, 3, 0x17, OP_SPECIAL_MATRIX );
508			OPMAP[ M44 ] = new OpCode( M44, 3, 0x18, OP_SPECIAL_MATRIX );
509			OPMAP[ M34 ] = new OpCode( M34, 3, 0x19, OP_SPECIAL_MATRIX );		
510			OPMAP[ DDX ] = new OpCode( DDX, 2, 0x1a, OP_VERSION2 | OP_FRAG_ONLY );
511			OPMAP[ DDY ] = new OpCode( DDY, 2, 0x1b, OP_VERSION2 | OP_FRAG_ONLY );			
512			OPMAP[ IFE ] = new OpCode( IFE, 2, 0x1c, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
513			OPMAP[ INE ] = new OpCode( INE, 2, 0x1d, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
514			OPMAP[ IFG ] = new OpCode( IFG, 2, 0x1e, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );			
515			OPMAP[ IFL ] = new OpCode( IFL, 2, 0x1f, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_SCALAR );
516			OPMAP[ ELS ] = new OpCode( ELS, 0, 0x20, OP_NO_DEST | OP_VERSION2 | OP_INCNEST | OP_DECNEST | OP_SCALAR );
517			OPMAP[ EIF ] = new OpCode( EIF, 0, 0x21, OP_NO_DEST | OP_VERSION2 | OP_DECNEST | OP_SCALAR );
518			// space			
519			OPMAP[ TED ] = new OpCode( TED, 3, 0x26, OP_FRAG_ONLY | OP_SPECIAL_TEX | OP_VERSION2);			
520			OPMAP[ KIL ] = new OpCode( KIL, 1, 0x27, OP_NO_DEST | OP_FRAG_ONLY );
521			OPMAP[ TEX ] = new OpCode( TEX, 3, 0x28, OP_FRAG_ONLY | OP_SPECIAL_TEX );
522			OPMAP[ SGE ] = new OpCode( SGE, 3, 0x29, 0 );
523			OPMAP[ SLT ] = new OpCode( SLT, 3, 0x2a, 0 );
524			OPMAP[ SGN ] = new OpCode( SGN, 2, 0x2b, 0 );
525			OPMAP[ SEQ ] = new OpCode( SEQ, 3, 0x2c, 0 );
526			OPMAP[ SNE ] = new OpCode( SNE, 3, 0x2d, 0 );			
527		
528			
529			SAMPLEMAP[ RGBA ]		= new Sampler( RGBA,		SAMPLER_TYPE_SHIFT,			0 );
530			SAMPLEMAP[ DXT1 ]		= new Sampler( DXT1,		SAMPLER_TYPE_SHIFT,			1 );
531			SAMPLEMAP[ DXT5 ]		= new Sampler( DXT5,		SAMPLER_TYPE_SHIFT,			2 );
532			SAMPLEMAP[ VIDEO ]		= new Sampler( VIDEO,		SAMPLER_TYPE_SHIFT,			3 );
533			SAMPLEMAP[ D2 ]			= new Sampler( D2,			SAMPLER_DIM_SHIFT,			0 );
534			SAMPLEMAP[ D3 ]			= new Sampler( D3,			SAMPLER_DIM_SHIFT,			2 );
535			SAMPLEMAP[ CUBE ]		= new Sampler( CUBE,		SAMPLER_DIM_SHIFT,			1 );
536			SAMPLEMAP[ MIPNEAREST ]	= new Sampler( MIPNEAREST,	SAMPLER_MIPMAP_SHIFT,		1 );
537			SAMPLEMAP[ MIPLINEAR ]	= new Sampler( MIPLINEAR,	SAMPLER_MIPMAP_SHIFT,		2 );
538			SAMPLEMAP[ MIPNONE ]	= new Sampler( MIPNONE,		SAMPLER_MIPMAP_SHIFT,		0 );
539			SAMPLEMAP[ NOMIP ]		= new Sampler( NOMIP,		SAMPLER_MIPMAP_SHIFT,		0 );
540			SAMPLEMAP[ NEAREST ]	= new Sampler( NEAREST,		SAMPLER_FILTER_SHIFT,		0 );
541			SAMPLEMAP[ LINEAR ]		= new Sampler( LINEAR,		SAMPLER_FILTER_SHIFT,		1 );
542			SAMPLEMAP[ CENTROID ]	= new Sampler( CENTROID,	SAMPLER_SPECIAL_SHIFT,		1 << 0 );
543			SAMPLEMAP[ SINGLE ]		= new Sampler( SINGLE,		SAMPLER_SPECIAL_SHIFT,		1 << 1 );
544			SAMPLEMAP[ IGNORESAMPLER ]	= new Sampler( IGNORESAMPLER,		SAMPLER_SPECIAL_SHIFT,		1 << 2 );
545			SAMPLEMAP[ REPEAT ]		= new Sampler( REPEAT,		SAMPLER_REPEAT_SHIFT,		1 );
546			SAMPLEMAP[ WRAP ]		= new Sampler( WRAP,		SAMPLER_REPEAT_SHIFT,		1 );
547			SAMPLEMAP[ CLAMP ]		= new Sampler( CLAMP,		SAMPLER_REPEAT_SHIFT,		0 );
548		}
549		
550		// ======================================================================
551		//	Constants
552		// ----------------------------------------------------------------------
553		private static const OPMAP:Dictionary					= new Dictionary();
554		private static const REGMAP:Dictionary					= new Dictionary();
555		private static const SAMPLEMAP:Dictionary				= new Dictionary();
556		
557		private static const MAX_NESTING:int					= 4;
558		private static const MAX_OPCODES:int					= 2048;
559		
560		private static const FRAGMENT:String					= "fragment";
561		private static const VERTEX:String						= "vertex";
562		
563		// masks and shifts
564		private static const SAMPLER_TYPE_SHIFT:uint			= 8;
565		private static const SAMPLER_DIM_SHIFT:uint				= 12;
566		private static const SAMPLER_SPECIAL_SHIFT:uint			= 16;
567		private static const SAMPLER_REPEAT_SHIFT:uint			= 20;
568		private static const SAMPLER_MIPMAP_SHIFT:uint			= 24;
569		private static const SAMPLER_FILTER_SHIFT:uint			= 28;
570		
571		// regmap flags
572		private static const REG_WRITE:uint						= 0x1;
573		private static const REG_READ:uint						= 0x2;
574		private static const REG_FRAG:uint						= 0x20;
575		private static const REG_VERT:uint						= 0x40;
576		
577		// opmap flags
578		private static const OP_SCALAR:uint						= 0x1;
579		private static const OP_SPECIAL_TEX:uint				= 0x8;
580		private static const OP_SPECIAL_MATRIX:uint				= 0x10;
581		private static const OP_FRAG_ONLY:uint					= 0x20;
582		private static const OP_VERT_ONLY:uint					= 0x40;
583		private static const OP_NO_DEST:uint					= 0x80;
584		private static const OP_VERSION2:uint 					= 0x100;		
585		private static const OP_INCNEST:uint 					= 0x200;
586		private static const OP_DECNEST:uint					= 0x400;
587		
588		// opcodes
589		private static const MOV:String							= "mov";
590		private static const ADD:String							= "add";
591		private static const SUB:String							= "sub";
592		private static const MUL:String							= "mul";
593		private static const DIV:String							= "div";
594		private static const RCP:String							= "rcp";
595		private static const MIN:String							= "min";
596		private static const MAX:String							= "max";
597		private static const FRC:String							= "frc";
598		private static const SQT:String							= "sqt";
599		private static const RSQ:String							= "rsq";
600		private static const POW:String							= "pow";
601		private static const LOG:String							= "log";
602		private static const EXP:String							= "exp";
603		private static const NRM:String							= "nrm";
604		private static const SIN:String							= "sin";
605		private static const COS:String							= "cos";
606		private static const CRS:String							= "crs";
607		private static const DP3:String							= "dp3";
608		private static const DP4:String							= "dp4";
609		private static const ABS:String							= "abs";
610		private static const NEG:String							= "neg";
611		private static const SAT:String							= "sat";
612		private static const M33:String							= "m33";
613		private static const M44:String							= "m44";
614		private static const M34:String							= "m34";
615		private static const DDX:String							= "ddx";
616		private static const DDY:String							= "ddy";		
617		private static const IFE:String							= "ife";
618		private static const INE:String							= "ine";
619		private static const IFG:String							= "ifg";
620		private static const IFL:String							= "ifl";
621		private static const ELS:String							= "els";
622		private static const EIF:String							= "eif";
623		private static const TED:String							= "ted";
624		private static const KIL:String							= "kil";
625		private static const TEX:String							= "tex";
626		private static const SGE:String							= "sge";
627		private static const SLT:String							= "slt";
628		private static const SGN:String							= "sgn";
629		private static const SEQ:String							= "seq";
630		private static const SNE:String							= "sne";		
631		
632		// registers
633		private static const VA:String							= "va";
634		private static const VC:String							= "vc";
635		private static const VT:String							= "vt";
636		private static const VO:String							= "vo";
637		private static const VI:String							= "vi";
638		private static const FC:String							= "fc";
639		private static const FT:String							= "ft";
640		private static const FS:String							= "fs";
641		private static const FO:String							= "fo";			
642		private static const FD:String							= "fd"; 
643		
644		// samplers
645		private static const D2:String							= "2d";
646		private static const D3:String							= "3d";
647		private static const CUBE:String						= "cube";
648		private static const MIPNEAREST:String					= "mipnearest";
649		private static const MIPLINEAR:String					= "miplinear";
650		private static const MIPNONE:String						= "mipnone";
651		private static const NOMIP:String						= "nomip";
652		private static const NEAREST:String						= "nearest";
653		private static const LINEAR:String						= "linear";
654		private static const CENTROID:String					= "centroid";
655		private static const SINGLE:String						= "single";
656		private static const IGNORESAMPLER:String				= "ignoresampler";
657		private static const REPEAT:String						= "repeat";
658		private static const WRAP:String						= "wrap";
659		private static const CLAMP:String						= "clamp";
660		private static const RGBA:String						= "rgba";
661		private static const DXT1:String						= "dxt1";
662		private static const DXT5:String						= "dxt5";
663		private static const VIDEO:String						= "video";
664	}
665}
666
667// ================================================================================
668//	Helper Classes
669// --------------------------------------------------------------------------------
670{
671	// ===========================================================================
672	//	Class
673	// ---------------------------------------------------------------------------
674	class OpCode
675	{		
676		// ======================================================================
677		//	Properties
678		// ----------------------------------------------------------------------
679		private var _emitCode:uint;
680		private var _flags:uint;
681		private var _name:String;
682		private var _numRegister:uint;
683		
684		// ======================================================================
685		//	Getters
686		// ----------------------------------------------------------------------
687		public function get emitCode():uint		{ return _emitCode; }
688		public function get flags():uint		{ return _flags; }
689		public function get name():String		{ return _name; }
690		public function get numRegister():uint	{ return _numRegister; }
691		
692		// ======================================================================
693		//	Constructor
694		// ----------------------------------------------------------------------
695		public function OpCode( name:String, numRegister:uint, emitCode:uint, flags:uint)
696		{
697			_name = name;
698			_numRegister = numRegister;
699			_emitCode = emitCode;
700			_flags = flags;
701		}		
702		
703		// ======================================================================
704		//	Methods
705		// ----------------------------------------------------------------------
706		public function toString():String
707		{
708			return "[OpCode name=\""+_name+"\", numRegister="+_numRegister+", emitCode="+_emitCode+", flags="+_flags+"]";
709		}
710	}
711	
712	// ===========================================================================
713	//	Class
714	// ---------------------------------------------------------------------------
715	class Register
716	{
717		// ======================================================================
718		//	Properties
719		// ----------------------------------------------------------------------
720		private var _emitCode:uint;
721		private var _name:String;
722		private var _longName:String;
723		private var _flags:uint;
724		private var _range:uint;
725		
726		// ======================================================================
727		//	Getters
728		// ----------------------------------------------------------------------
729		public function get emitCode():uint		{ return _emitCode; }
730		public function get longName():String	{ return _longName; }
731		public function get name():String		{ return _name; }
732		public function get flags():uint		{ return _flags; }
733		public function get range():uint		{ return _range; }
734		
735		// ======================================================================
736		//	Constructor
737		// ----------------------------------------------------------------------
738		public function Register( name:String, longName:String, emitCode:uint, range:uint, flags:uint)
739		{
740			_name = name;
741			_longName = longName;
742			_emitCode = emitCode;
743			_range = range;
744			_flags = flags;
745		}
746		
747		// ======================================================================
748		//	Methods
749		// ----------------------------------------------------------------------
750		public function toString():String
751		{
752			return "[Register name=\""+_name+"\", longName=\""+_longName+"\", emitCode="+_emitCode+", range="+_range+", flags="+ _flags+"]";
753		}
754	}
755	
756	// ===========================================================================
757	//	Class
758	// ---------------------------------------------------------------------------
759	class Sampler
760	{
761		// ======================================================================
762		//	Properties
763		// ----------------------------------------------------------------------
764		private var _flag:uint;
765		private var _mask:uint;
766		private var _name:String;
767		
768		// ======================================================================
769		//	Getters
770		// ----------------------------------------------------------------------
771		public function get flag():uint		{ return _flag; }
772		public function get mask():uint		{ return _mask; }
773		public function get name():String	{ return _name; }
774		
775		// ======================================================================
776		//	Constructor
777		// ----------------------------------------------------------------------
778		public function Sampler( name:String, flag:uint, mask:uint )
779		{
780			_name = name;
781			_flag = flag;
782			_mask = mask;
783		}
784		
785		// ======================================================================
786		//	Methods
787		// ----------------------------------------------------------------------
788		public function toString():String
789		{
790			return "[Sampler name=\""+_name+"\", flag=\""+_flag+"\", mask="+mask+"]";
791		}
792	}
793}