AGAL 2 Linker support added. mrt, depth write, conditionals, ddx, ddy,

ted
This commit is contained in:
gonchar
2012-12-16 19:42:51 +01:00
parent eb525b22db
commit 97221a1c13
7 changed files with 384 additions and 470 deletions

View File

@@ -189,7 +189,6 @@ package alternativa.engine3d.materials {
private static var samplerFilter:Vector.<String> = Vector.<String>(["nearest", "linear"]); private static var samplerFilter:Vector.<String> = Vector.<String>(["nearest", "linear"]);
private static var swizzleType:Vector.<String> = Vector.<String>(["x", "y", "z", "w"]); private static var swizzleType:Vector.<String> = Vector.<String>(["x", "y", "z", "w"]);
private static var twoOperandsCommands:Dictionary; private static var twoOperandsCommands:Dictionary;
private static const O_CODE:uint = "o".charCodeAt(0);
// TODO: option to turn off auto-prefixes // TODO: option to turn off auto-prefixes
public static function disassemble(byteCode:ByteArray):String { public static function disassemble(byteCode:ByteArray):String {
@@ -207,6 +206,7 @@ package alternativa.engine3d.materials {
twoOperandsCommands[0x17] = true; twoOperandsCommands[0x17] = true;
twoOperandsCommands[0x18] = true; twoOperandsCommands[0x18] = true;
twoOperandsCommands[0x19] = true; twoOperandsCommands[0x19] = true;
twoOperandsCommands[0x26] = true;
twoOperandsCommands[0x28] = true; twoOperandsCommands[0x28] = true;
twoOperandsCommands[0x29] = true; twoOperandsCommands[0x29] = true;
twoOperandsCommands[0x2a] = true; twoOperandsCommands[0x2a] = true;
@@ -237,7 +237,6 @@ package alternativa.engine3d.materials {
} }
private static function getCommand(byteCode:ByteArray, programType:String):String { private static function getCommand(byteCode:ByteArray, programType:String):String {
var cmd:uint = byteCode.readUnsignedInt(); var cmd:uint = byteCode.readUnsignedInt();
var command:String = CommandType.COMMAND_NAMES[cmd]; var command:String = CommandType.COMMAND_NAMES[cmd];
var result:String; var result:String;
@@ -264,16 +263,11 @@ package alternativa.engine3d.materials {
} }
var destType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); var destType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0);
if (destType.charCodeAt(0) == O_CODE) { result = command + " " + attachProgramPrefix(destType, programType) + destNumber.toString() + s + ", ";
result = command + " " + attachProgramPrefix(destType, programType) + s + ", ";
} else {
result = command + " " + attachProgramPrefix(destType, programType) + destNumber.toString() + s + ", ";
}
result += attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); result += attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType);
if (twoOperandsCommands[cmd]) { if (twoOperandsCommands[cmd]) {
if (cmd == CommandType.TEX) { if (cmd == CommandType.TEX || cmd == CommandType.TED) {
result += ", " + attachProgramPrefix(getSamplerVariable(byteCode), programType); result += ", " + attachProgramPrefix(getSamplerVariable(byteCode), programType);
} else { } else {
result += ", " + attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); result += ", " + attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType);
@@ -281,15 +275,22 @@ package alternativa.engine3d.materials {
} else { } else {
byteCode.readDouble(); byteCode.readDouble();
} }
if (cmd == CommandType.ELS || cmd == CommandType.EIF) {
result = " " + command;
}
return result; return result;
} }
private static function attachProgramPrefix(variable:String, programType:String):String { private static function attachProgramPrefix(variable:String, programType:String):String {
var char:uint = variable.charCodeAt(0); var char : uint = variable.charCodeAt(0);
if (char == "o".charCodeAt(0)) if (char == "o".charCodeAt(0)) {
return variable + (programType == "f" ? "c" : "p"); return variable + (programType == "f" ? "c" : "p");
else if (char != "v".charCodeAt(0)) } else if (char == "d".charCodeAt(0)) {
return "o"+variable;
} else if (char != "v".charCodeAt(0)) {
return programType + variable; return programType + variable;
}
return variable; return variable;
} }

View File

@@ -5,113 +5,144 @@
* *
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */ * */
package alternativa.engine3d.materials.compiler { package alternativa.engine3d.materials.compiler {
/** import flash.utils.Dictionary;
/**
* @private * @private
*/ */
public class CommandType { public class CommandType {
public static const MOV : uint = 0x00;
public static const MOV:uint = 0x00;
public static const ADD:uint = 0x01;
public static const SUB:uint = 0x02;
public static const MUL:uint = 0x03;
public static const DIV:uint = 0x04;
public static const RCP:uint = 0x05;
public static const MIN:uint = 0x06;
public static const MAX:uint = 0x07;
public static const FRC:uint = 0x08;
public static const SQT:uint = 0x09;
public static const RSQ:uint = 0x0a;
public static const POW:uint = 0x0b;
public static const LOG:uint = 0x0c;
public static const EXP:uint = 0x0d;
public static const NRM:uint = 0x0e;
public static const SIN:uint = 0x0f;
public static const COS:uint = 0x10;
public static const CRS:uint = 0x11;
public static const DP3:uint = 0x12;
public static const DP4:uint = 0x13;
public static const ABS:uint = 0x14;
public static const NEG:uint = 0x15;
public static const SAT:uint = 0x16;
public static const M33:uint = 0x17;
public static const M44:uint = 0x18;
public static const M34:uint = 0x19;
public static const KIL:uint = 0x27;
public static const TEX:uint = 0x28;
public static const SGE:uint = 0x29;
public static const SLT:uint = 0x2a;
public static const SEQ:uint = 0x2c;
public static const SNE:uint = 0x2d;
public static const DEF:uint = 0x80;
public static const CAL:uint = 0x81;
public static const COMMAND_NAMES:Vector.<String> = Vector.<String>(
["mov", "add", "sub", "mul", "div", "rcp", "min", "max", "frc", "sqt", "rsq", "pow", "log", "exp",
"nrm", "sin", "cos", "crs", "dp3", "dp4", "abs", "neg", "sat", "m33", "m44", "m34","1a","1b","1c","1d","1e","1f","20","21","22","23","24","25","26", "kil", "tex", "sge", "slt", "2b", "seq", "sne"]
);
public static const commands:Object = formCommandsList(); public static const ADD : uint = 0x01;
private static function formCommandsList():Object { public static const SUB : uint = 0x02;
// dp3( ,) +- */
var result:Object = {};
result[","] = new CommandType(0, 1);
result[")"] = new CommandType(0, 1);
result["+"] = new CommandType(2, 2);
result["-"] = new CommandType(2, 2);
result["*"] = new CommandType(2, 3);
result["/"] = new CommandType(2, 3);
result["mov"] = new CommandType(1);
result["add"] = new CommandType();
result["sub"] = new CommandType();
result["mul"] = new CommandType();
result["div"] = new CommandType();
result["rcp"] = new CommandType(1);
result["min"] = new CommandType();
result["max"] = new CommandType();
result["frc"] = new CommandType(1);
result["sqt"] = new CommandType(1);
result["rsq"] = new CommandType(1);
result["pow"] = new CommandType();
result["log"] = new CommandType(1);
result["exp"] = new CommandType(1);
result["nrm"] = new CommandType(1);
result["sin"] = new CommandType(1);
result["cos"] = new CommandType(1);
result["crs"] = new CommandType();
result["dp3"] = new CommandType();
result["dp4"] = new CommandType();
result["abs"] = new CommandType(1);
result["neg"] = new CommandType(1);
result["sat"] = new CommandType(1);
result["m33"] = new CommandType();
result["m44"] = new CommandType();
result["m34"] = new CommandType();
// result["kil"] = new CommandType();
// result["tex"] = new CommandType();
result["sge"] = new CommandType();
result["slt"] = new CommandType();
result["seq"] = new CommandType();
result["sne"] = new CommandType();
// setting ids
for (var s:String in result) {
result[s].id = s;
}
result["+"].id = "add";
result["-"].id = "sub";
result["*"].id = "mul";
result["/"].id = "div";
return result;
}
public var id:String; public static const MUL : uint = 0x03;
public var priority:int;
public var numInputs:int;
public function CommandType(numInputs:int = 2, priority:int = 0) { public static const DIV : uint = 0x04;
this.numInputs = numInputs;
this.priority = priority; public static const RCP : uint = 0x05;
}
public static const MIN : uint = 0x06;
public static const MAX : uint = 0x07;
public static const FRC : uint = 0x08;
public static const SQT : uint = 0x09;
public static const RSQ : uint = 0x0a;
public static const POW : uint = 0x0b;
public static const LOG : uint = 0x0c;
public static const EXP : uint = 0x0d;
public static const NRM : uint = 0x0e;
public static const SIN : uint = 0x0f;
public static const COS : uint = 0x10;
public static const CRS : uint = 0x11;
public static const DP3 : uint = 0x12;
public static const DP4 : uint = 0x13;
public static const ABS : uint = 0x14;
public static const NEG : uint = 0x15;
public static const SAT : uint = 0x16;
public static const M33 : uint = 0x17;
public static const M44 : uint = 0x18;
public static const M34 : uint = 0x19;
public static const DDX : uint = 0x1a;
public static const DDY : uint = 0x1b;
public static const IFE : uint = 0x1c;
public static const INE : uint = 0x1d;
public static const IFG : uint = 0x1e;
public static const IFL : uint = 0x1f;
public static const ELS : uint = 0x20;
public static const EIF : uint = 0x21;
public static const TED : uint = 0x26;
public static const KIL : uint = 0x27;
public static const TEX : uint = 0x28;
// set if greater equal
public static const SGE : uint = 0x29;
// set if less than
public static const SLT : uint = 0x2a;
// set if greater than
public static const SGN : uint = 0x2b;
// set if equal
public static const SEQ : uint = 0x2c;
// set if not equal
public static const SNE : uint = 0x2d;
public static const COMMAND_NAMES : Dictionary = new Dictionary();
COMMAND_NAMES[MOV] = "mov";
COMMAND_NAMES[ADD] = "add";
COMMAND_NAMES[SUB] = "sub";
COMMAND_NAMES[MUL] = "mul";
COMMAND_NAMES[DIV] = "div";
COMMAND_NAMES[RCP] = "rcp";
COMMAND_NAMES[MIN] = "min";
COMMAND_NAMES[MAX] = "max";
COMMAND_NAMES[FRC] = "frc";
COMMAND_NAMES[SQT] = "sqt";
COMMAND_NAMES[RSQ] = "rsq";
COMMAND_NAMES[POW] = "pow";
COMMAND_NAMES[LOG] = "log";
COMMAND_NAMES[EXP] = "exp";
COMMAND_NAMES[NRM] = "nrm";
COMMAND_NAMES[SIN] = "sin";
COMMAND_NAMES[COS] = "cos";
COMMAND_NAMES[CRS] = "crs";
COMMAND_NAMES[DP3] = "dp3";
COMMAND_NAMES[DP4] = "dp4";
COMMAND_NAMES[ABS] = "abs";
COMMAND_NAMES[NEG] = "neg";
COMMAND_NAMES[SAT] = "sat";
COMMAND_NAMES[M33] = "m33";
COMMAND_NAMES[M44] = "m44";
COMMAND_NAMES[M34] = "m34";
COMMAND_NAMES[DDX] = "ddx";
COMMAND_NAMES[DDY] = "ddy";
COMMAND_NAMES[IFE] = "ife";
COMMAND_NAMES[INE] = "ine";
COMMAND_NAMES[IFG] = "ifg";
COMMAND_NAMES[IFL] = "ifl";
COMMAND_NAMES[ELS] = "els";
COMMAND_NAMES[EIF] = "eif";
COMMAND_NAMES[TED] = "ted";
COMMAND_NAMES[KIL] = "kil";
COMMAND_NAMES[TEX] = "tex";
COMMAND_NAMES[SGE] = "sge";
COMMAND_NAMES[SLT] = "slt";
COMMAND_NAMES[SGN] = "sgn";
COMMAND_NAMES[SEQ] = "seq";
COMMAND_NAMES[SNE] = "sne";
} }
} }

View File

@@ -16,7 +16,7 @@ package alternativa.engine3d.materials.compiler {
public class DestinationVariable extends Variable { public class DestinationVariable extends Variable {
public function DestinationVariable(source:String) { public function DestinationVariable(source:String) {
var strType:String = source.match(/[tovi]/)[0]; var strType : String = source.match(/[tovid]/)[0];
index = parseInt(source.match(/\d+/)[0], 10); index = parseInt(source.match(/\d+/)[0], 10);
var swizzle:Array = source.match(/\.[xyzw]{1,4}/); var swizzle:Array = source.match(/\.[xyzw]{1,4}/);
var regmask:uint; var regmask:uint;
@@ -32,7 +32,8 @@ package alternativa.engine3d.materials.compiler {
regmask |= 1 << cv; regmask |= 1 << cv;
} }
} else { } else {
regmask = 0xf; // id swizzle or mask regmask = 0xf;
// id swizzle or mask
} }
lowerCode = (regmask << 16) | index; lowerCode = (regmask << 16) | index;
@@ -49,10 +50,14 @@ package alternativa.engine3d.materials.compiler {
lowerCode |= 0x4000000; lowerCode |= 0x4000000;
type = 4; type = 4;
break; break;
case "i": case "d":
lowerCode |= 0x6000000; lowerCode |= 0x6000000;
type = 6; type = 6;
break; break;
case "i":
lowerCode |= 0x7000000;
type = 7;
break;
default : default :
throw new ArgumentError("Wrong destination register type, must be \"t\" or \"o\" or \"v\", var = " + source); throw new ArgumentError("Wrong destination register type, must be \"t\" or \"o\" or \"v\", var = " + source);
break; break;

View File

@@ -51,7 +51,7 @@ package alternativa.engine3d.materials.compiler {
alternativa3d var _linkedVariables:Object; alternativa3d var _linkedVariables:Object;
// Dictionary of temporary variables at this linker. Key is a name of variable, value is a variable. // Dictionary of temporary variables at this linker. Key is a name of variable, value is a variable.
private var _localVariables:Object = {}; private var _localVariables:Object = new Object();
// Key - procedure, value - array of strings. // Key - procedure, value - array of strings.
private var _inputParams:Dictionary = new Dictionary(); private var _inputParams:Dictionary = new Dictionary();
@@ -59,11 +59,11 @@ package alternativa.engine3d.materials.compiler {
private var _outputParams:Dictionary = new Dictionary(); private var _outputParams:Dictionary = new Dictionary();
// Counters of variables by types // Counters of variables by types
private var _locals:Vector.<uint> = new Vector.<uint>(6, true); private var _locals:Vector.<uint> = new Vector.<uint>(7, true);
private var samplers:Object = {}; private var samplers:Object = new Object();
private var _varyings:Object = {}; private var _varyings:Object = new Object();
/** /**
* Creates a new Linker instance. * Creates a new Linker instance.
@@ -79,10 +79,10 @@ package alternativa.engine3d.materials.compiler {
*/ */
public function clear():void { public function clear():void {
data = null; data = null;
_locals[0] = _locals[1] = _locals[2] = _locals[3] = _locals[4] = _locals[5] = 0; _locals[0] = _locals[1] = _locals[2] = _locals[3] = _locals[4] = _locals[5] = _locals[6] = 0;
procedures.length = 0; procedures.length = 0;
_varyings = {}; _varyings = new Object();
samplers = {}; samplers = new Object();
commandsCount = 0; commandsCount = 0;
slotsCount = 0; slotsCount = 0;
@@ -214,11 +214,11 @@ package alternativa.engine3d.materials.compiler {
/** /**
* Linking of procedures to one shader. * Linking of procedures to one shader.
*/ */
public function link():void { public function link(version:uint = 1):void {
if (data != null) return; if (data != null) return;
var v:Variable; var v:Variable;
var variables:Object = _linkedVariables = {}; var variables:Object = _linkedVariables = new Object();
var p:Procedure; var p:Procedure;
var i:int, j:int; var i:int, j:int;
var nv:Variable; var nv:Variable;
@@ -232,8 +232,11 @@ package alternativa.engine3d.materials.compiler {
data = new ByteArray(); data = new ByteArray();
data.endian = Endian.LITTLE_ENDIAN; data.endian = Endian.LITTLE_ENDIAN;
data.writeByte(0xa0); data.writeByte(0xa0);
data.writeUnsignedInt(0x1); // AGAL version, big endian, bit pattern will be 0x01000000 // tag version
data.writeByte(0xa1); // tag program id data.writeUnsignedInt(version);
// AGAL version, big endian, bit pattern will be 0x01000000
data.writeByte(0xa1);
// tag program id
data.writeByte((type == Context3DProgramType.FRAGMENT) ? 1 : 0); // vertex or fragment data.writeByte((type == Context3DProgramType.FRAGMENT) ? 1 : 0); // vertex or fragment
commandsCount = 0; commandsCount = 0;
@@ -245,17 +248,18 @@ package alternativa.engine3d.materials.compiler {
_locals[3] = 0; _locals[3] = 0;
_locals[4] = 0; _locals[4] = 0;
_locals[5] = 0; _locals[5] = 0;
_locals[6] = 0;
// First iteration - collecting of variables. // First iteration - collecting of variables.
for each (p in procedures) { for each (p in procedures) {
var iLength:int = p.variablesUsages.length;
_locals[1] += p.reservedConstants; _locals[1] += p.reservedConstants;
var iLength:int = p.variablesUsages.length;
for (i = 0; i < iLength; i++) { for (i = 0; i < iLength; i++) {
var vector:Vector.<Variable> = p.variablesUsages[i]; var vector:Vector.<Variable> = p.variablesUsages[i];
var jLength:int = vector.length; var jLength:int = vector.length;
for (j = 0; j < jLength; j++) { for (j = 0; j < jLength; j++) {
v = vector[j]; v = vector[j];
if (v == null || v.name == null) continue; if (v == null || v.name == null) continue;
if (v.name == null && i != 2 && i != 6 && i != 3) { if (v.name == null && i != 2 && i != 6 && i != 3 && i != 7) {
throw new Error("Linkage error: Noname variable. Procedure = " + p.name + ", type = " + i.toString() + ", index = " + j.toString()); throw new Error("Linkage error: Noname variable. Procedure = " + p.name + ", type = " + i.toString() + ", index = " + j.toString());
} }
nv = variables[v.name] = new Variable(); nv = variables[v.name] = new Variable();
@@ -284,8 +288,8 @@ package alternativa.engine3d.materials.compiler {
if (v == null) { if (v == null) {
throw new Error("Input parameter not set. paramName = " + param); throw new Error("Input parameter not set. paramName = " + param);
} }
if (p.variablesUsages[6].length > j) { if (p.variablesUsages[7].length > j) {
var inParam:Variable = p.variablesUsages[6][j]; var inParam:Variable = p.variablesUsages[7][j];
if (inParam == null) { if (inParam == null) {
throw new Error("Input parameter set, but not exist in code. paramName = " + param + ", register = i" + j.toString()); throw new Error("Input parameter set, but not exist in code. paramName = " + param + ", register = i" + j.toString());
} }
@@ -350,6 +354,7 @@ package alternativa.engine3d.materials.compiler {
slotsCount += p.slotsCount; slotsCount += p.slotsCount;
} }
} }
private function resolveVariablesUsages(code:ByteArray, variables:Object, variableUsages:Vector.<Variable>, type:uint, offset:int):void { private function resolveVariablesUsages(code:ByteArray, variables:Object, variableUsages:Vector.<Variable>, type:uint, offset:int):void {
for (var j:int = 0; j < variableUsages.length; j++) { for (var j:int = 0; j < variableUsages.length; j++) {
var vUsage:Variable = variableUsages[j]; var vUsage:Variable = variableUsages[j];

View File

@@ -5,33 +5,30 @@
* *
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */ * */
package alternativa.engine3d.materials.compiler { package alternativa.engine3d.materials.compiler {
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.alternativa3d; import flash.display3D.Context3DProgramType;
import flash.utils.ByteArray;
import flash.display3D.Context3DProgramType; import flash.utils.Endian;
import flash.utils.ByteArray;
import flash.utils.Endian;
use namespace alternativa3d;
use namespace alternativa3d;
/** /**
* @private * @private
* Shader procedure * Shader procedure
*/ */
public class Procedure { public class Procedure {
// Name of procedure // Name of procedure
public var name:String; public var name : String;
/**
* @private
*/
alternativa3d static const crc32Table:Vector.<uint> = createCRC32Table();
private static function createCRC32Table():Vector.<uint> { /**
var crc_table:Vector.<uint> = new Vector.<uint>(256); * @private
var crc:uint, i:int, j:int; */
alternativa3d static const crc32Table : Vector.<uint> = createCRC32Table();
private static function createCRC32Table() : Vector.<uint> {
var crc_table : Vector.<uint> = new Vector.<uint>(256);
var crc : uint, i : int, j : int;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
crc = i; crc = i;
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
@@ -41,37 +38,40 @@ use namespace alternativa3d;
} }
return crc_table; return crc_table;
} }
/**
* @private /**
*/ * @private
alternativa3d var crc32:uint = 0; */
alternativa3d var crc32 : uint = 0;
/** /**
* Code of procedure. * Code of procedure.
*/ */
public var byteCode:ByteArray = new ByteArray(); public var byteCode : ByteArray = new ByteArray();
public var variablesUsages:Vector.<Vector.<Variable>> = new Vector.<Vector.<Variable>>();
public var variablesUsages : Vector.<Vector.<Variable>> = new Vector.<Vector.<Variable>>();
/** /**
* Number of instruction slots in a procedure. * Number of instruction slots in a procedure.
*/ */
public var slotsCount:int = 0; public var slotsCount : int = 0;
/** /**
* Number of strings in a procedure. * Number of strings in a procedure.
*/ */
public var commandsCount:int = 0; public var commandsCount : int = 0;
/**
* @private /**
*/ * @private
alternativa3d var reservedConstants:uint = 0; */
alternativa3d var reservedConstants : uint = 0;
/** /**
* Creates a new Procedure instance. * Creates a new Procedure instance.
* *
* @param array Array of AGAL strings * @param array Array of AGAL strings
*/ */
public function Procedure(array:Array = null, name:String = null) { public function Procedure(array : Array = null, name : String = null) {
byteCode.endian = Endian.LITTLE_ENDIAN; byteCode.endian = Endian.LITTLE_ENDIAN;
this.name = name; this.name = name;
if (array != null) { if (array != null) {
@@ -79,20 +79,23 @@ use namespace alternativa3d;
} }
} }
public function getByteCode(type:String):ByteArray { public function getByteCode(type : String, version:uint = 1) : ByteArray {
var result:ByteArray = new ByteArray(); var result : ByteArray = new ByteArray();
result.endian = Endian.LITTLE_ENDIAN; result.endian = Endian.LITTLE_ENDIAN;
result.writeByte(0xa0); result.writeByte(0xa0);
result.writeUnsignedInt(0x1); // AGAL version, big endian, bit pattern will be 0x01000000 result.writeUnsignedInt(version);
result.writeByte(0xa1); // tag program id // AGAL version, big endian, bit pattern will be 0x01000000
result.writeByte((type == Context3DProgramType.FRAGMENT) ? 1 : 0); // vertex or fragment result.writeByte(0xa1);
// tag program id
result.writeByte((type == Context3DProgramType.FRAGMENT) ? 1 : 0);
// vertex or fragment
result.writeBytes(byteCode); result.writeBytes(byteCode);
return result; return result;
} }
private function addVariableUsage(v:Variable):void { private function addVariableUsage(v : Variable) : void {
var vars:Vector.<Variable> = variablesUsages[v.type]; var vars : Vector.<Variable> = variablesUsages[v.type];
var index:int = v.index; var index : int = v.index;
if (index >= vars.length) { if (index >= vars.length) {
vars.length = index + 1; vars.length = index + 1;
} else { } else {
@@ -111,8 +114,8 @@ use namespace alternativa3d;
* *
* @see VariableType * @see VariableType
*/ */
public function assignVariableName(type:uint, index:uint, name:String, size:uint = 1):void { public function assignVariableName(type : uint, index : uint, name : String, size : uint = 1) : void {
var v:Variable = variablesUsages[type][index]; var v : Variable = variablesUsages[type][index];
while (v != null) { while (v != null) {
v.size = size; v.size = size;
v.name = name; v.name = name;
@@ -123,45 +126,39 @@ use namespace alternativa3d;
/** /**
* Compiles shader from the string. * Compiles shader from the string.
*/ */
public function compileFromString(source:String):void { public function compileFromString(source : String) : void {
var commands:Array = source.split("\n"); var commands : Array = source.split("\n");
compileFromArray(commands); compileFromArray(commands);
} }
/** /**
* Compiles shader from the array of strings. * Compiles shader from the array of strings.
*/ */
public function compileFromArray(source:Array):void { public function compileFromArray(source : Array) : void {
for (var i:int = 0; i < 7; i++) { for (var i : int = 0; i < 8; i++) {
variablesUsages[i] = new Vector.<Variable>(); variablesUsages[i] = new Vector.<Variable>();
} }
byteCode.length = 0; byteCode.length = 0;
commandsCount = 0; commandsCount = 0;
slotsCount = 0; slotsCount = 0;
const decPattern:RegExp = /# *[acvs]\d{1,3} *= *[a-zA-Z0-9_]*/i; const decPattern : RegExp = /# *[acvs]\d{1,3} *= *[a-zA-Z0-9_]*/i;
const rpnPattern:RegExp = /[tivo]\d+(\.[xyzw]{1,4})? *=/; var declarationStrings : Vector.<String> = new Vector.<String>();
var count : int = source.length;
var declarationStrings:Vector.<String> = new Vector.<String>();
var count:int = source.length;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
var cmd:String = source[i]; var cmd : String = source[i];
var declaration:Array = cmd.match(decPattern); var declaration : Array = cmd.match(decPattern);
if (declaration != null && declaration.length > 0) { if (declaration != null && declaration.length > 0) {
declarationStrings.push(declaration[0]); declarationStrings.push(declaration[0]);
} else { } else {
if (rpnPattern.test(cmd)) { writeAGALExpression(cmd);
writeRPNExpression(cmd);
} else {
writeAGALExpression(cmd);
}
} }
} }
for (i = 0,count = declarationStrings.length; i < count; i++) { for (i = 0,count = declarationStrings.length; i < count; i++) {
var decArray:Array = declarationStrings[i].split("="); var decArray : Array = declarationStrings[i].split("=");
var regType:String = decArray[0].match(/[acvs]/i); var regType : String = decArray[0].match(/[acvs]/i);
var varIndex:int = int(decArray[0].match(/\d{1,3}/i)); var varIndex : int = int(decArray[0].match(/\d{1,3}/i));
var varName:String = decArray[1].match(/[a-zA-Z0-9]*/i); var varName : String = decArray[1].match(/[a-zA-Z0-9]*/i);
switch (regType.toLowerCase()) { switch (regType.toLowerCase()) {
case "a": case "a":
assignVariableName(VariableType.ATTRIBUTE, varIndex, varName); assignVariableName(VariableType.ATTRIBUTE, varIndex, varName);
@@ -180,256 +177,70 @@ use namespace alternativa3d;
crc32 = createCRC32(byteCode); crc32 = createCRC32(byteCode);
} }
public function assignConstantsArray(registersCount:uint = 1):void { public function assignConstantsArray(registersCount : uint = 1) : void {
reservedConstants = registersCount; reservedConstants = registersCount;
} }
private function writeRPNExpression(source:String):void { private const agalParser : RegExp = /[A-Za-z]+(((\[.+\])|(\d+))(\.[xyzw]{1,4})?(\ *\<.*>)?)?/g;
// 1) Output in the same variable
// 2) Check for errors and complex expressions
// 3) Compile through AGAL
// 4) Only +-/* operators and one assignment =
// 5) output mask supported for : (.x, .y, .z, .w, .xy, .xyz, .xyzw)
// 6) swizzle supported
// 7) swizzle handled like in AGAL compiler
// TODO: handle swizzle smartly (.zw -> .zwzw) private function writeAGALExpression(source : String) : void {
// TODO: implement operators inputs size check var commentIndex : int = source.indexOf("//");
// TODO: implement operators auto output size
// TODO: implement operators output swizzle
// TODO: minimize output temporaries count (sort operators by priority)
// TODO: write to ByteArray directly
// TODO: implement negate unary operator (-x)
// TODO: implement tex (tex2D, texCube) in any form
// TODO: implement groups and complex expressions
// TODO: support additional output masks
// TODO: optimize variables components usage (sort by swizzles length)
// TODO: optimize
// TODO: implement alternate assignments
var commentIndex:int = source.indexOf("//");
if (commentIndex >= 0) {
source = source.substr(0, commentIndex);
}
var operands:Array = source.match(/[a-z]+(((\[.+\])|(\d+))(\.[xyzw]{1,4})?)?|[+\-*\/=(),]/g);
var numOperands:int = operands.length;
if (numOperands < 3) return;
if (operands[1] != "=") {
throw new Error("Syntax error");
}
var i:int;
var output:String = operands[0];
var maskIndex:int = output.lastIndexOf(".");
var outputMaskLen:int = (maskIndex >= 0) ? output.length - maskIndex - 1 : 4;
if (outputMaskLen != 1 && maskIndex >= 0) {
// check mask
const X_CHAR_CODE:int = "x".charCodeAt(0);
for (i = 0; i < outputMaskLen; i++) {
var code:int = (i == 3) ? X_CHAR_CODE -1 : X_CHAR_CODE + i; // .w
if (output.charCodeAt(maskIndex + i + 1) != code) {
throw new Error("Output mask with such type not supported " + output + ".");
}
}
}
var outputVar:String = (maskIndex >= 0) ? output.substr(0, maskIndex) : output;
if (outputMaskLen == 4) output = outputVar;
var operators:Vector.<CommandType> = new Vector.<CommandType>();
var variables:Vector.<String> = new Vector.<String>();
function getPriority(command:CommandType):int {
return command.priority;
}
function getSwizzleLen(value:String):uint {
var i:int = value.lastIndexOf(".");
return (i < 0 ? 4 : value.length - i - 1);
}
function writeCommand(command:CommandType, numInputs:int, operandIndex:int, isLastOperator:Boolean):void {
if (numInputs != command.numInputs) {
throw new Error("Syntax error. Operator " + command.id + " inputs count wrong. Expected " + command.numInputs + ".");
}
var b:String = (numInputs > 1) ? variables.pop() : null;
var a:String = variables.pop();
if (a == null || (numInputs > 1 && b == null)) throw new Error("Syntax error. Variable expected after " + command + ".");
// Check can we use output for writing
var i:int;
for (i = 0; i < variables.length; i++) {
if (variables[i].indexOf(output) >= 0) {
// output already used
throw new Error("Expression is too complex. Groups unsupported.");
}
}
for (i = operandIndex + 1; i < numOperands; i++) {
if (operands[i].indexOf(output) >= 0) {
// output is used as source
throw new Error("Expression is too complex. Output used as source.");
}
}
var maxSwizzle:uint;
if (numInputs <= 1) {
maxSwizzle = getSwizzleLen(a);
} else {
var aSwizzleLen:uint = getSwizzleLen(a);
var bSwizzleLen:uint = getSwizzleLen(b);
if (aSwizzleLen != bSwizzleLen && aSwizzleLen != 1 && bSwizzleLen != 1) {
throw new Error("Variables size mistmatch " + a + " and " + b + ".");
}
maxSwizzle = (aSwizzleLen > bSwizzleLen) ? aSwizzleLen : bSwizzleLen;
}
if (maxSwizzle > outputMaskLen || (isLastOperator && maxSwizzle != outputMaskLen && maxSwizzle != 1)) {
throw new Error("Expression differs in size with output " + output + ".");
}
var out:String = output;
if (!isLastOperator && maxSwizzle != outputMaskLen) {
// TODO: use same components like in variables (.zw + .zw -> .zw)
if (maxSwizzle == 1) {
out = outputVar + ".x";
} else if (maxSwizzle == 2) {
out = outputVar + ".xy";
} else if (maxSwizzle == 3) {
out = outputVar + ".xyz";
}
}
if (numInputs > 1) {
writeAGALExpression(command.id + " " + out + " " + a + " " + b);
} else {
writeAGALExpression(command.id + " " + out + " " + a);
}
variables.push(out);
}
var operand:String;
if (numOperands == 3) {
operand = operands[2];
if (getSwizzleLen(operand) != outputMaskLen && getSwizzleLen(operand) != 1) {
throw new Error("Expression differs in size with output " + output + ".");
}
writeAGALExpression("mov " + output + " " + operand);
}
var command:CommandType;
var wasVariable:Boolean = false;
for (i = 2; i < numOperands; i++) {
operand = operands[i];
switch (operand) {
case "+":
case "-":
case "*":
case "/":
if (!wasVariable) throw new Error("Syntax error. Variable expected before " + operand + ".");
command = CommandType.commands[operand];
// process operators from stack while their priority is higher or equal
while (operators.length > 0 && getPriority(operators[operators.length - 1]) >= getPriority(command)) {
writeCommand(operators.pop(), 2, i, false);
}
operators.push(command);
wasVariable = false;
break;
case ")":
case ",":
if (!wasVariable) throw new Error("Syntax error. Variable expected before " + operand + ".");
command = CommandType.commands[operand];
// process all commands before until comma or left bracket
while (operators.length > 0 && getPriority(operators[operators.length - 1]) > getPriority(command)) {
writeCommand(operators.pop(), 2, i, false);
}
if (operand == ",") {
operators.push(command);
wasVariable = false;
} else {
// count all commas until function
var numParams:int = 1;
while ((command = operators.pop()) != null && command.priority != 0) {
numParams++;
}
writeCommand(command, numParams, i, i == numOperands - 1);
wasVariable = true;
}
break;
default:
if (wasVariable) throw new Error("Syntax error. Operator expected before " + operand + ".");
command = CommandType.commands[operand];
if (command != null) {
// is command
// test bracket
if (i + 1 >= numOperands || operands[i + 1] != "(") {
throw new Error("Syntax error. Expected bracket after " + operand + ".");
}
operators.push(command);
i++; // skip bracket
// wasVariable = false;
} else {
// is variable
variables.push(operand);
wasVariable = true;
}
break;
}
}
// process remained operators
while ((command = operators.pop()) != null) {
writeCommand(command, 2, numOperands, operators.length == 0);
}
if (variables.length > 1) throw new Error("Syntax error. Unknown novel error.");
}
private const agalParser:RegExp = /[A-Za-z]+(((\[.+\])|(\d+))(\.[xyzw]{1,4})?(\ *\<.*>)?)?/g;
private function writeAGALExpression(source:String):void {
var commentIndex:int = source.indexOf("//");
if (commentIndex >= 0) { if (commentIndex >= 0) {
source = source.substr(0, commentIndex); source = source.substr(0, commentIndex);
} }
// Errors: // Errors:
//1) Merged commands // 1) Merged commands
//2) Syntax errors // 2) Syntax errors
//-- incorrect number of operands // -- incorrect number of operands
//-- unknown commands // -- unknown commands
//-- unknown registers // -- unknown registers
//-- unknown constructions // -- unknown constructions
//3) Using of unwritable registers // 3) Using of unwritable registers
//-- in vertex shader (va0, c0, s0); // -- in vertex shader (va0, c0, s0);
//-- in fragment shader (v0, va0, c0, s0); // -- in fragment shader (v0, va0, c0, s0);
//4) Using of unreadable registers // 4) Using of unreadable registers
//-- in vertex shader (v0, s0); // -- in vertex shader (v0, s0);
//-- in fragment shader (va0); // -- in fragment shader (va0);
//5) Deny write into the input registers // 5) Deny write into the input registers
//6) Mismatch the size of types of registers // 6) Mismatch the size of types of registers
//7) Relative addressing in the fragment shader is not possible // 7) Relative addressing in the fragment shader is not possible
//-- You can not use it for recording // -- You can not use it for recording
//-- Offset is out of range [0..255] // -- Offset is out of range [0..255]
//8) Flow errors // 8) Flow errors
//-- unused variable // -- unused variable
//-- using of uninitialized variable // -- using of uninitialized variable
//-- using of partially uninitialized variable // -- using of partially uninitialized variable
//-- function is not return value // -- function is not return value
//9) Restrictions // 9) Restrictions
//-- too many commands // -- too many commands
//-- too many constants // -- too many constants
//-- too many textures // -- too many textures
//-- too many temporary variables // -- too many temporary variables
//-- too many interpolated values // -- too many interpolated values
// You can not use kil in fragment shader // You can not use kil in fragment shader
var operands:Array = source.match(agalParser); var operands : Array = source.match(agalParser);
// It is possible not use the input parameter. It is optimization of the linker // It is possible not use the input parameter. It is optimization of the linker
// Determine the size of constant // Determine the size of constant
if (operands.length < 2) { var opCode : String = operands[0];
return; var destination : DestinationVariable;
} var source1 : SourceVariable;
var opCode:String = operands[0]; var source2 : Variable;
var destination:Variable; if (opCode == "kil" || opCode == "ife" || opCode == "ine" || opCode == "ifg" || opCode == "ifl") {//no dist
var source1:SourceVariable;
var source2:Variable;
if (opCode == "kil") {
source1 = new SourceVariable(operands[1]); source1 = new SourceVariable(operands[1]);
addVariableUsage(source1);
} else if (opCode == "els" || opCode == "eif") { // no dist no sources
source1 = null;
source2 = null;
} else { } else {
destination = new DestinationVariable(operands[1]); destination = new DestinationVariable(operands[1]);
source1 = new SourceVariable(operands[2]);
addVariableUsage(destination); addVariableUsage(destination);
source1 = new SourceVariable(operands[2]);
addVariableUsage(source1);
} }
addVariableUsage(source1); var type : uint;
var type:uint;
switch (opCode) { switch (opCode) {
case "mov": case "mov":
type = CommandType.MOV; type = CommandType.MOV;
@@ -561,6 +372,52 @@ use namespace alternativa3d;
addVariableUsage(source2); addVariableUsage(source2);
slotsCount += 3; slotsCount += 3;
break; break;
case "ddx":
type = CommandType.DDX;
slotsCount += 2;
break;
case "ddy":
type = CommandType.DDY;
slotsCount += 2;
break;
case "ife":
type = CommandType.IFE;
source2 = new SourceVariable(operands[2]);
addVariableUsage(source2);
slotsCount++;
break;
case "ine":
type = CommandType.INE;
source2 = new SourceVariable(operands[2]);
addVariableUsage(source2);
slotsCount++;
break;
case "ifg":
type = CommandType.IFG;
source2 = new SourceVariable(operands[2]);
addVariableUsage(source2);
slotsCount++;
break;
case "ifl":
type = CommandType.IFL;
source2 = new SourceVariable(operands[2]);
addVariableUsage(source2);
slotsCount++;
break;
case "els":
type = CommandType.ELS;
slotsCount++;
break;
case "eif":
type = CommandType.EIF;
slotsCount++;
break;
case "ted":
type = CommandType.TED;
source2 = new SamplerVariable(operands[3]);
addVariableUsage(source2);
slotsCount++;
break;
case "kil": case "kil":
type = CommandType.KIL; type = CommandType.KIL;
slotsCount++; slotsCount++;
@@ -583,6 +440,10 @@ use namespace alternativa3d;
addVariableUsage(source2); addVariableUsage(source2);
slotsCount++; slotsCount++;
break; break;
case "sgn":
type = CommandType.SGN;
slotsCount++;
break;
case "seq": case "seq":
type = CommandType.SEQ; type = CommandType.SEQ;
source2 = new SourceVariable(operands[3]); source2 = new SourceVariable(operands[3]);
@@ -599,6 +460,8 @@ use namespace alternativa3d;
// TODO: throw error - unknown command // TODO: throw error - unknown command
break; break;
} }
// Fill of byteCode of command // Fill of byteCode of command
byteCode.writeUnsignedInt(type); byteCode.writeUnsignedInt(type);
if (destination != null) { if (destination != null) {
@@ -607,16 +470,20 @@ use namespace alternativa3d;
} else { } else {
byteCode.writeUnsignedInt(0); byteCode.writeUnsignedInt(0);
} }
source1.position = byteCode.position; if (source1 != null) {
if (source1.relative != null) { source1.position = byteCode.position;
addVariableUsage(source1.relative); if (source1.relative != null) {
source1.relative.position = byteCode.position; addVariableUsage(source1.relative);
source1.relative.position = byteCode.position;
}
byteCode.writeUnsignedInt(source1.lowerCode);
byteCode.writeUnsignedInt(source1.upperCode);
} else {
byteCode.position = (byteCode.length += 8);
} }
byteCode.writeUnsignedInt(source1.lowerCode);
byteCode.writeUnsignedInt(source1.upperCode);
if (source2 != null) { if (source2 != null) {
source2.position = byteCode.position; source2.position = byteCode.position;
var s2v:SourceVariable = source2 as SourceVariable; var s2v : SourceVariable = source2 as SourceVariable;
if (s2v != null && s2v.relative != null) { if (s2v != null && s2v.relative != null) {
addVariableUsage(s2v.relative); addVariableUsage(s2v.relative);
s2v.relative.position = s2v.position; s2v.relative.position = s2v.position;
@@ -632,16 +499,16 @@ use namespace alternativa3d;
/** /**
* Creates and returns an instance of procedure from array of strings. * Creates and returns an instance of procedure from array of strings.
*/ */
public static function compileFromArray(source:Array, name:String = null):Procedure { public static function compileFromArray(source : Array, name : String = null) : Procedure {
var proc:Procedure = new Procedure(source, name); var proc : Procedure = new Procedure(source, name);
return proc; return proc;
} }
/** /**
* Creates and returns an instance of procedure from string. * Creates and returns an instance of procedure from string.
*/ */
public static function compileFromString(source:String, name:String = null):Procedure { public static function compileFromString(source : String, name : String = null) : Procedure {
var proc:Procedure = new Procedure(null, name); var proc : Procedure = new Procedure(null, name);
proc.compileFromString(source); proc.compileFromString(source);
return proc; return proc;
} }
@@ -649,8 +516,8 @@ use namespace alternativa3d;
/** /**
* Create an instance of procedure. * Create an instance of procedure.
*/ */
public function newInstance():Procedure { public function newInstance() : Procedure {
var res:Procedure = new Procedure(); var res : Procedure = new Procedure();
res.byteCode = this.byteCode; res.byteCode = this.byteCode;
res.variablesUsages = this.variablesUsages; res.variablesUsages = this.variablesUsages;
res.slotsCount = this.slotsCount; res.slotsCount = this.slotsCount;
@@ -659,19 +526,19 @@ use namespace alternativa3d;
res.name = name; res.name = name;
return res; return res;
} }
/**
* @private /**
*/ * @private
alternativa3d static function createCRC32(byteCode:ByteArray):uint { */
alternativa3d static function createCRC32(byteCode : ByteArray) : uint {
byteCode.position = 0; byteCode.position = 0;
var len:uint = byteCode.length; var len : uint = byteCode.length;
var crc:uint = 0xFFFFFFFF; var crc : uint = 0xFFFFFFFF;
while (len--) { while (len--) {
var byte:int = byteCode.readByte(); var byte : int = byteCode.readByte();
crc = crc32Table[(crc ^ byte) & 0xFF] ^ (crc >> 8); crc = crc32Table[(crc ^ byte) & 0xFF] ^ (crc >> 8);
} }
return crc ^ 0xFFFFFFFF; return crc ^ 0xFFFFFFFF;
} }
} }
} }

View File

@@ -5,58 +5,57 @@
* *
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */ * */
package alternativa.engine3d.materials.compiler { package alternativa.engine3d.materials.compiler {
import flash.utils.ByteArray; import flash.utils.ByteArray;
/** /**
* @private * @private
*/ */
public class SourceVariable extends Variable { public class SourceVariable extends Variable {
public var relative : RelativeVariable;
public var relative:RelativeVariable; override public function get size() : uint {
if (relative) {
override public function get size():uint {
if(relative){
return 0; return 0;
} }
return super.size; return super.size;
} }
public function SourceVariable(source:String) { public function SourceVariable(source : String) {
var strType:String = String(source.match(/[catsoiv]/g)[0]); var strType : String = String(source.match(/[catsoivd]/g)[0]);
var regmask:uint; var regmask : uint;
var relreg:Array = source.match( /\[.*\]/g ); var relreg : Array = source.match(/\[.*\]/g);
var isRel:Boolean = relreg.length > 0; var isRel : Boolean = relreg.length > 0;
if(isRel){ if (isRel) {
source = source.replace(relreg[0], "0"); source = source.replace(relreg[0], "0");
} else { } else {
index = parseInt(source.match(/\d+/g)[0], 10); index = parseInt(source.match(/\d+/g)[0], 10);
} }
var swizzle:Array = source.match(/\.[xyzw]{1,4}/); var swizzle : Array = source.match(/\.[xyzw]{1,4}/);
var maskmatch:String = swizzle ? swizzle[0] : null; var maskmatch : String = swizzle ? swizzle[0] : null;
if (maskmatch) { if (maskmatch) {
regmask = 0; regmask = 0;
var cv:int; var cv : int;
var maskLength:uint = maskmatch.length; var maskLength : uint = maskmatch.length;
for (var i:int = 1; i < maskLength; i++) { for (var i : int = 1; i < maskLength; i++) {
cv = maskmatch.charCodeAt(i) - X_CHAR_CODE; cv = maskmatch.charCodeAt(i) - X_CHAR_CODE;
if (cv == -1) cv = 3; if (cv == -1) cv = 3;
regmask |= cv << ( ( i - 1 ) << 1 ); regmask |= cv << ( ( i - 1 ) << 1 );
} }
for ( ; i <= 4; i++ ) for ( ; i <= 4; i++ )
regmask |= cv << ( ( i - 1 ) << 1 ); // repeat last regmask |= cv << ( ( i - 1 ) << 1 );
// repeat last
} else { } else {
regmask = 0xe4; // id swizzle or mask regmask = 0xe4;
// id swizzle or mask
} }
lowerCode = (regmask << 24) | index; lowerCode = (regmask << 24) | index;
switch(strType){ switch(strType) {
case "a": case "a":
type = VariableType.ATTRIBUTE; type = VariableType.ATTRIBUTE;
break; break;
@@ -75,8 +74,11 @@ package alternativa.engine3d.materials.compiler {
case "i": case "i":
type = VariableType.INPUT; type = VariableType.INPUT;
break; break;
case "d":
type = VariableType.DEPTH;
break;
default : default :
throw new ArgumentError('Wrong source register type, must be "a" or "c" or "t" or "o" or "v" or "i", var = ' + source); throw new ArgumentError('Wrong source register type, must be "a" or "c" or "t" or "o" or "v" or "i" or "d", var = ' + source);
break; break;
} }
upperCode = type; upperCode = type;
@@ -87,8 +89,8 @@ package alternativa.engine3d.materials.compiler {
isRelative = true; isRelative = true;
} }
} }
override public function writeToByteArray(byteCode:ByteArray, newIndex:int, newType:int, offset:int = 0):void { override public function writeToByteArray(byteCode : ByteArray, newIndex : int, newType : int, offset : int = 0) : void {
if (relative == null) { if (relative == null) {
super.writeToByteArray(byteCode, newIndex, newType, offset); super.writeToByteArray(byteCode, newIndex, newType, offset);
} else { } else {
@@ -97,6 +99,5 @@ package alternativa.engine3d.materials.compiler {
byteCode.position = position + offset + 4; byteCode.position = position + offset + 4;
byteCode.writeByte(newType); byteCode.writeByte(newType);
} }
} }
} }

View File

@@ -38,13 +38,17 @@ package alternativa.engine3d.materials.compiler {
* Texture. * Texture.
*/ */
public static const SAMPLER:uint = 5; public static const SAMPLER:uint = 5;
/**
* Depth variable.
*/
public static const DEPTH:uint = 6;
/** /**
* Input variable. * Input variable.
*/ */
public static const INPUT:uint = 6; public static const INPUT:uint = 7;
public static const TYPE_NAMES:Vector.<String> = Vector.<String>( public static const TYPE_NAMES:Vector.<String> = Vector.<String>(
["attribute", "constant", "temporary", "output", "varying", "sampler", "input"] ["attribute", "constant", "temporary", "output", "varying", "sampler", "depth", "input"]
); );
public function VariableType() { public function VariableType() {
} }