mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-26 01:49:07 -07:00
Procedure: complex operators for RPN expressions
This commit is contained in:
@@ -7,8 +7,7 @@
|
||||
* */
|
||||
|
||||
package alternativa.engine3d.materials.compiler {
|
||||
|
||||
/**
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public class CommandType {
|
||||
@@ -51,7 +50,68 @@ package alternativa.engine3d.materials.compiler {
|
||||
["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 function CommandType() {
|
||||
|
||||
public static const commands:Object = formCommandsList();
|
||||
|
||||
private static function formCommandsList():Object {
|
||||
// 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 var priority:int;
|
||||
public var numInputs:int;
|
||||
|
||||
public function CommandType(numInputs:int = 2, priority:int = 0) {
|
||||
this.numInputs = numInputs;
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
package alternativa.engine3d.materials.compiler {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.display3D.Context3DProgramType;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
import flash.display3D.Context3DProgramType;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
|
||||
use namespace alternativa3d;
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -188,7 +188,9 @@ package alternativa.engine3d.materials.compiler {
|
||||
// 7) swizzle handled like in AGAL compiler
|
||||
|
||||
// TODO: handle swizzle smartly (.zw -> .zwzw)
|
||||
// TODO: implement complex operators (dp3, nrm, sat)
|
||||
// TODO: implement operators inputs size check
|
||||
// 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)
|
||||
@@ -203,7 +205,7 @@ package alternativa.engine3d.materials.compiler {
|
||||
if (commentIndex >= 0) {
|
||||
source = source.substr(0, commentIndex);
|
||||
}
|
||||
var operands:Array = source.match(/([activo]((\[.+\])|(\d+))(\.[xyzw]{1,4})?|[+\-*\/=])/g);
|
||||
var operands:Array = source.match(/[a-z]+(((\[.+\])|(\d+))(\.[xyzw]{1,4})?)?|[+\-*\/=(),]/g);
|
||||
var numOperands:int = operands.length;
|
||||
if (numOperands < 3) return;
|
||||
if (operands[1] != "=") {
|
||||
@@ -226,19 +228,22 @@ package alternativa.engine3d.materials.compiler {
|
||||
var outputVar:String = (maskIndex >= 0) ? output.substr(0, maskIndex) : output;
|
||||
if (outputMaskLen == 4) output = outputVar;
|
||||
|
||||
var operators:Vector.<String> = new Vector.<String>();
|
||||
var operators:Vector.<CommandType> = new Vector.<CommandType>();
|
||||
var variables:Vector.<String> = new Vector.<String>();
|
||||
function getPriority(command:String):int {
|
||||
return ((command == "+" || command == "-") ? 1 : 2);
|
||||
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:String, operandIndex:int, isLastOperator:Boolean):void {
|
||||
var b:String = variables.pop();
|
||||
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 || b == null) throw new Error("Syntax error. Variable expected after " + command + ".");
|
||||
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++) {
|
||||
@@ -253,12 +258,17 @@ package alternativa.engine3d.materials.compiler {
|
||||
throw new Error("Expression is too complex. Output used as source.");
|
||||
}
|
||||
}
|
||||
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 + ".");
|
||||
}
|
||||
var maxSwizzle:uint = (aSwizzleLen > bSwizzleLen) ? aSwizzleLen : bSwizzleLen;
|
||||
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 + ".");
|
||||
}
|
||||
@@ -273,19 +283,10 @@ package alternativa.engine3d.materials.compiler {
|
||||
out = outputVar + ".xyz";
|
||||
}
|
||||
}
|
||||
switch (command) {
|
||||
case "+":
|
||||
writeAGALExpression("add " + out + " " + a + " " + b);
|
||||
break;
|
||||
case "-":
|
||||
writeAGALExpression("sub " + out + " " + a + " " + b);
|
||||
break;
|
||||
case "*":
|
||||
writeAGALExpression("mul " + out + " " + a + " " + b);
|
||||
break;
|
||||
case "/":
|
||||
writeAGALExpression("div " + out + " " + a + " " + b);
|
||||
break;
|
||||
if (numInputs > 1) {
|
||||
writeAGALExpression(command.id + " " + out + " " + a + " " + b);
|
||||
} else {
|
||||
writeAGALExpression(command.id + " " + out + " " + a);
|
||||
}
|
||||
variables.push(out);
|
||||
}
|
||||
@@ -297,6 +298,7 @@ package alternativa.engine3d.materials.compiler {
|
||||
}
|
||||
writeAGALExpression("mov " + output + " " + operand);
|
||||
}
|
||||
var command:CommandType;
|
||||
var wasVariable:Boolean = false;
|
||||
for (i = 2; i < numOperands; i++) {
|
||||
operand = operands[i];
|
||||
@@ -306,23 +308,59 @@ package alternativa.engine3d.materials.compiler {
|
||||
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(operand)) {
|
||||
writeCommand(operators.pop(), i, false);
|
||||
while (operators.length > 0 && getPriority(operators[operators.length - 1]) >= getPriority(command)) {
|
||||
writeCommand(operators.pop(), 2, i, false);
|
||||
}
|
||||
operators.push(operand);
|
||||
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 + ".");
|
||||
variables.push(operand);
|
||||
wasVariable = true;
|
||||
|
||||
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 ((operand = operators.pop()) != null) {
|
||||
writeCommand(operand, numOperands, operators.length == 0);
|
||||
while ((command = operators.pop()) != null) {
|
||||
writeCommand(command, 2, numOperands, operators.length == 0);
|
||||
}
|
||||
if (variables.length > 1) throw new Error("Syntax error. Unknown novel error.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user