diff --git a/src/alternativa/engine3d/materials/A3DUtils.as b/src/alternativa/engine3d/materials/A3DUtils.as index 37f4355..70d6481 100644 --- a/src/alternativa/engine3d/materials/A3DUtils.as +++ b/src/alternativa/engine3d/materials/A3DUtils.as @@ -1,349 +1,349 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ - -package alternativa.engine3d.materials { - - import alternativa.engine3d.alternativa3d; - import alternativa.engine3d.materials.compiler.CommandType; - import alternativa.engine3d.materials.compiler.VariableType; - - import avmplus.getQualifiedSuperclassName; - - import flash.display3D.Context3D; - import flash.display3D.Context3DTextureFormat; - import flash.display3D.IndexBuffer3D; - import flash.display3D.VertexBuffer3D; - import flash.display3D.textures.Texture; - import flash.geom.Point; - import flash.utils.ByteArray; - import flash.utils.Dictionary; - import flash.utils.Endian; - import flash.utils.getDefinitionByName; - - /** - * @private - */ - public class A3DUtils { - - public static const NONE:int = 0; - public static const DXT1:int = 1; - public static const ETC1:int = 2; - public static const PVRTC:int = 3; - - private static const DXT1Data:ByteArray = getDXT1(); - private static const PVRTCData:ByteArray = getPVRTC(); - private static const ETC1Data:ByteArray = getETC1(); - - private static function getDXT1():ByteArray { - var DXT1Data:Vector. = Vector.([65,84,70,0,2,71,2,2,2,3,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,7,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); - return getData(DXT1Data); - } - - private static function getETC1():ByteArray { - var ETC1Data:Vector. = Vector.([65,84,70,0,2,104,2,2,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,7,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0]); - return getData(ETC1Data); - } - - private static function getPVRTC():ByteArray { - var PVRTCData:Vector. = Vector.([65,84,70,0,2,173,2,2,2,3,0,0,0,0,0,0,0,0,13,0,0,0,16,0,0,0,104,190,153,255,0,0,0,0,15,91,0,0,16,0,0,102,12,228,2,255,225,0,0,0,0,0,223,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,132,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,165,192,0,7,227,99,186,53,197,40,185,134,182,32,130,98,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,143,192,120,64,6,16,34,52,192,196,65,132,90,98,68,16,17,68,60,91,8,48,76,35,192,97,132,71,76,33,164,97,1,2,194,12,19,8,240,29,132,24,38,17,224,48,194,35,166,16,210,48,128,128,24,68,121,132,52,204,32,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,0,233,56,90,0,0,0,0,12,0,0,0,16,0,0,127,237,210,0,0,0,0,0,155,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,64,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,0,233,56,90,0,0,0,0,12,0,0,0,16,0,0,127,237,210,0,0,0,0,0,155,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,64,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,200,0,0,0,0,0,0,0,0,0,0]); - return getData(PVRTCData); - } - - private static function getData(source:Vector.):ByteArray { - var result:ByteArray = new ByteArray(); - for (var i:int = 0, length:int = source.length; i < length; i++) { - result.writeByte(source[i]); - } - return result; - } - - public static function getSizeFromATF(byteArray:ByteArray, size:Point):void { - byteArray.position = 7; - var w:int = byteArray.readByte(); - var h:int = byteArray.readByte(); - size.x = 1 << w; - size.y = 1 << h; - byteArray.position = 0; - } - - public static function getSupportedTextureFormat(context3D:Context3D):int { - var testTexture:Texture = context3D.createTexture(4, 4, Context3DTextureFormat.COMPRESSED, false); - var result:int = NONE; - try { - testTexture.uploadCompressedTextureFromByteArray(DXT1Data, 0); - result = DXT1; - } catch(e:Error) { - result = NONE; - } - if (result == NONE) { - try { - testTexture.uploadCompressedTextureFromByteArray(PVRTCData, 0); - result = PVRTC; - } catch(e:Error) { - result = NONE; - } - } - if (result == NONE) { - try { - testTexture.uploadCompressedTextureFromByteArray(ETC1Data, 0); - result = ETC1; - } catch(e:Error) { - result = NONE; - } - } - testTexture.dispose(); - return result; - } - - public static function vectorNumberToByteArray(vector:Vector.):ByteArray { - var result:ByteArray = new ByteArray(); - result.endian = Endian.LITTLE_ENDIAN; - for (var i:int = 0; i < vector.length; i++) { - result.writeFloat(vector[i]); - } - result.position = 0; - return result; - } - - public static function byteArrayToVectorUint(byteArray:ByteArray):Vector. { - var result:Vector. = new Vector.(); - var length:uint = 0; - byteArray.position = 0; - byteArray.endian = Endian.LITTLE_ENDIAN; - while (byteArray.bytesAvailable > 0) { - result[length++] = byteArray.readUnsignedShort(); - } - return result; - } - - public static function createVertexBufferFromByteArray(context:Context3D, byteArray:ByteArray, numVertices:uint, stride:uint = 3):VertexBuffer3D { - if (context == null) { - throw new ReferenceError("context is not set"); - } - var buffer:VertexBuffer3D = context.createVertexBuffer(numVertices, stride); - buffer.uploadFromByteArray(byteArray, 0, 0, numVertices); - return buffer; - } - - public static function createVertexBufferFromVector(context:Context3D, vector:Vector., numVertices:uint, stride:uint = 3):VertexBuffer3D { - if (context == null) { - throw new ReferenceError("context is not set"); - } - var buffer:VertexBuffer3D = context.createVertexBuffer(numVertices, stride); - - var byteArray:ByteArray = A3DUtils.vectorNumberToByteArray(vector); - buffer.uploadFromByteArray(byteArray, 0, 0, numVertices); - return buffer; - } - - public static function createTextureFromByteArray(context:Context3D, byteArray:ByteArray, width:Number, height:Number, format:String):Texture { - if (context == null) { - throw new ReferenceError("context is not set"); - } - var texture:Texture = context.createTexture(width, height, format, false); - texture.uploadCompressedTextureFromByteArray(byteArray, 0); - - return texture; - } - - public static function createIndexBufferFromByteArray(context:Context3D, byteArray:ByteArray, numIndices:uint):IndexBuffer3D { - if (context == null) { - throw new ReferenceError("context is not set"); - } - var buffer:IndexBuffer3D = context.createIndexBuffer(numIndices); - buffer.uploadFromByteArray(byteArray, 0, 0, numIndices); - - return buffer; - } - - public static function createIndexBufferFromVector(context:Context3D, vector:Vector., numIndices:int = -1):IndexBuffer3D { - if (context == null) { - throw new ReferenceError("context is not set"); - } - var count:uint = numIndices > 0 ? numIndices : vector.length; - var buffer:IndexBuffer3D = context.createIndexBuffer(count); - buffer.uploadFromVector(vector, 0, count); - - var byteArray:ByteArray = new ByteArray(); - byteArray.endian = Endian.LITTLE_ENDIAN; - for (var i:int = 0; i < count; i++) { - byteArray.writeInt(vector[i]); - } - byteArray.position = 0; - - buffer.uploadFromVector(vector, 0, count); - - return buffer; - } - - // Disassembler - private static var programType:Vector. = Vector.(["VERTEX", "FRAGMENT"]); - private static var samplerDimension:Vector. = Vector.(["2D", "cube", "3D"]); - private static var samplerWraping:Vector. = Vector.(["clamp", "repeat"]); - private static var samplerMipmap:Vector. = Vector.(["mipnone", "mipnearest", "miplinear"]); - private static var samplerFilter:Vector. = Vector.(["nearest", "linear"]); - private static var swizzleType:Vector. = Vector.(["x", "y", "z", "w"]); - private static var twoOperandsCommands:Dictionary; - - // TODO: option to turn off auto-prefixes - public static function disassemble(byteCode:ByteArray):String { - if (!twoOperandsCommands) { - twoOperandsCommands = new Dictionary(); - twoOperandsCommands[0x1] = true; - twoOperandsCommands[0x2] = true; - twoOperandsCommands[0x3] = true; - twoOperandsCommands[0x4] = true; - twoOperandsCommands[0x6] = true; - twoOperandsCommands[0xb] = true; - twoOperandsCommands[0x11] = true; - twoOperandsCommands[0x12] = true; - twoOperandsCommands[0x13] = true; - twoOperandsCommands[0x17] = true; - twoOperandsCommands[0x18] = true; - twoOperandsCommands[0x19] = true; - twoOperandsCommands[0x26] = true; - twoOperandsCommands[0x28] = true; - twoOperandsCommands[0x29] = true; - twoOperandsCommands[0x2a] = true; - twoOperandsCommands[0x2c] = true; - twoOperandsCommands[0x2d] = true; - } - var res:String = ""; - byteCode.position = 0; - if (byteCode.bytesAvailable < 7) { - return "error in byteCode header"; - } - - res += "magic = " + byteCode.readUnsignedByte().toString(16); - res += "\nversion = " + byteCode.readInt().toString(10); - res += "\nshadertypeid = " + byteCode.readUnsignedByte().toString(16); - var pType:String = programType[byteCode.readByte()]; - res += "\nshadertype = " + pType; - res += "\nsource\n"; - pType = pType.substring(0, 1).toLowerCase(); - var lineNumber:uint = 1; - while (byteCode.bytesAvailable - 24 >= 0) { - res += (lineNumber++).toString() + ": " + getCommand(byteCode, pType) + "\n"; - } - if (byteCode.bytesAvailable > 0) { - res += "\nunexpected byteCode length. extra bytes:" + byteCode.bytesAvailable; - } - return res; - } - - private static function getCommand(byteCode:ByteArray, programType:String):String { - var cmd:uint = byteCode.readUnsignedInt(); - var command:String = CommandType.COMMAND_NAMES[cmd]; - var result:String; - var destNumber:uint = byteCode.readUnsignedShort(); - var swizzle:uint = byteCode.readByte(); - var s:String = ""; - var destSwizzle:uint = 4; - if (swizzle < 15) { - s += "."; - s += ((swizzle & 0x1) > 0) ? "x" : ""; - s += ((swizzle & 0x2) > 0) ? "y" : ""; - s += ((swizzle & 0x4) > 0) ? "z" : ""; - s += ((swizzle & 0x8) > 0) ? "w" : ""; - destSwizzle = s.length - 1; - } - - var sourceSwizzleLimit:int = destSwizzle; - if (cmd == CommandType.TEX) { - sourceSwizzleLimit = 2; - } else if (cmd == CommandType.DP3) { - sourceSwizzleLimit = 3; - } else if (cmd == CommandType.DP4) { - sourceSwizzleLimit = 4; - } - - var destType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); - result = command + " " + attachProgramPrefix(destType, programType) + destNumber.toString() + s + ", "; - result += attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); - - if (twoOperandsCommands[cmd]) { - if (cmd == CommandType.TEX || cmd == CommandType.TED) { - result += ", " + attachProgramPrefix(getSamplerVariable(byteCode), programType); - } else { - result += ", " + attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); - } - } else { - byteCode.readDouble(); - } - - if (cmd == CommandType.ELS || cmd == CommandType.EIF) { - result = " " + command; - } - return result; - } - - private static function attachProgramPrefix(variable:String, programType:String):String { - var char : uint = variable.charCodeAt(0); - if (char == "o".charCodeAt(0)) { - return variable + (programType == "f" ? "c" : "p"); - } else if (char == "d".charCodeAt(0)) { - return "o"+variable; - } else if (char != "v".charCodeAt(0)) { - return programType + variable; - } - return variable; - } - - private static function getSamplerVariable(byteCode:ByteArray):String { - var number:uint = byteCode.readUnsignedInt(); - byteCode.readByte(); - var dim:uint = byteCode.readByte() >> 4; - var wraping:uint = byteCode.readByte() >> 4; - var n:uint = byteCode.readByte(); - return "s" + number.toString() + " <" + samplerDimension[dim] + ", " + samplerWraping[wraping] - + ", " + samplerFilter[(n >> 4) & 0xf] + ", " + samplerMipmap[n & 0xf] + ">"; - } - - private static function getSourceVariable(byteCode:ByteArray, swizzleLimit:uint):String { - var s1Number:uint = byteCode.readUnsignedShort(); - var offset:uint = byteCode.readUnsignedByte(); - var s:String = getSourceSwizzle(byteCode.readUnsignedByte(), swizzleLimit); - - var s1Type:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); - var indexType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); - var comp:String = swizzleType[byteCode.readUnsignedByte()]; - - if (byteCode.readUnsignedByte() > 0) { - return s1Type + "[" + indexType + s1Number.toString() + "." + comp + ((offset > 0) ? ("+" + offset.toString()) : "") + "]" + s; - } - return s1Type + s1Number.toString() + s; - } - - private static function getSourceSwizzle(swizzle:uint, swizzleLimit:uint = 4):String { - var s:String = ""; - if (swizzle != 0xe4) { - s += "."; - s += swizzleType[(swizzle & 0x3)]; - s += swizzleType[(swizzle >> 2) & 0x3]; - s += swizzleType[(swizzle >> 4) & 0x3]; - s += swizzleType[(swizzle >> 6) & 0x3]; - s = swizzleLimit < 4 ? s.substring(0, swizzleLimit + 1) : s; - } - return s; - } - - alternativa3d static function checkParent(child:Class, parent:Class):Boolean { - var current:Class = child; - if (parent == null) return true; - while (true) { - if (current == parent) return true; - var className:String = getQualifiedSuperclassName(current); - if (className != null) { - current = getDefinitionByName(className) as Class; - } else return false; - } - return false; - } - - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ + +package alternativa.engine3d.materials { + + import alternativa.engine3d.alternativa3d; + import alternativa.engine3d.materials.compiler.CommandType; + import alternativa.engine3d.materials.compiler.VariableType; + + import avmplus.getQualifiedSuperclassName; + + import flash.display3D.Context3D; + import flash.display3D.Context3DTextureFormat; + import flash.display3D.IndexBuffer3D; + import flash.display3D.VertexBuffer3D; + import flash.display3D.textures.Texture; + import flash.geom.Point; + import flash.utils.ByteArray; + import flash.utils.Dictionary; + import flash.utils.Endian; + import flash.utils.getDefinitionByName; + + /** + * @private + */ + public class A3DUtils { + + public static const NONE:int = 0; + public static const DXT1:int = 1; + public static const ETC1:int = 2; + public static const PVRTC:int = 3; + + private static const DXT1Data:ByteArray = getDXT1(); + private static const PVRTCData:ByteArray = getPVRTC(); + private static const ETC1Data:ByteArray = getETC1(); + + private static function getDXT1():ByteArray { + var DXT1Data:Vector. = Vector.([65,84,70,0,2,71,2,2,2,3,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,85,105,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,10,87,77,80,72,79,84,79,0,25,0,192,122,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,224,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,7,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); + return getData(DXT1Data); + } + + private static function getETC1():ByteArray { + var ETC1Data:Vector. = Vector.([65,84,70,0,2,104,2,2,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,7,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,16,0,0,0,255,252,0,0,0,0,12,0,0,0,16,0,0,127,233,56,0,0,0,0,0,157,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,1,0,0,0,129,188,4,0,1,0,0,0,2,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,66,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,0,0,1,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,208,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,114,0,4,0]); + return getData(ETC1Data); + } + + private static function getPVRTC():ByteArray { + var PVRTCData:Vector. = Vector.([65,84,70,0,2,173,2,2,2,3,0,0,0,0,0,0,0,0,13,0,0,0,16,0,0,0,104,190,153,255,0,0,0,0,15,91,0,0,16,0,0,102,12,228,2,255,225,0,0,0,0,0,223,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,132,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,165,192,0,7,227,99,186,53,197,40,185,134,182,32,130,98,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,143,192,120,64,6,16,34,52,192,196,65,132,90,98,68,16,17,68,60,91,8,48,76,35,192,97,132,71,76,33,164,97,1,2,194,12,19,8,240,29,132,24,38,17,224,48,194,35,166,16,210,48,128,128,24,68,121,132,52,204,32,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,0,233,56,90,0,0,0,0,12,0,0,0,16,0,0,127,237,210,0,0,0,0,0,155,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,64,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,16,0,0,0,233,56,90,0,0,0,0,12,0,0,0,16,0,0,127,237,210,0,0,0,0,0,155,73,73,188,1,8,0,0,0,5,0,1,188,1,0,16,0,0,0,74,0,0,0,128,188,4,0,1,0,0,0,2,0,0,0,129,188,4,0,1,0,0,0,4,0,0,0,192,188,4,0,1,0,0,0,90,0,0,0,193,188,4,0,1,0,0,0,64,0,0,0,0,0,0,0,36,195,221,111,3,78,254,75,177,133,61,119,118,141,201,9,87,77,80,72,79,84,79,0,25,0,192,120,0,1,0,3,96,0,160,0,10,0,0,160,0,0,0,4,111,255,0,1,0,0,1,0,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,200,0,0,0,0,0,0,0,0,0,0]); + return getData(PVRTCData); + } + + private static function getData(source:Vector.):ByteArray { + var result:ByteArray = new ByteArray(); + for (var i:int = 0, length:int = source.length; i < length; i++) { + result.writeByte(source[i]); + } + return result; + } + + public static function getSizeFromATF(byteArray:ByteArray, size:Point):void { + byteArray.position = 7; + var w:int = byteArray.readByte(); + var h:int = byteArray.readByte(); + size.x = 1 << w; + size.y = 1 << h; + byteArray.position = 0; + } + + public static function getSupportedTextureFormat(context3D:Context3D):int { + var testTexture:Texture = context3D.createTexture(4, 4, Context3DTextureFormat.COMPRESSED, false); + var result:int = NONE; + try { + testTexture.uploadCompressedTextureFromByteArray(DXT1Data, 0); + result = DXT1; + } catch(e:Error) { + result = NONE; + } + if (result == NONE) { + try { + testTexture.uploadCompressedTextureFromByteArray(PVRTCData, 0); + result = PVRTC; + } catch(e:Error) { + result = NONE; + } + } + if (result == NONE) { + try { + testTexture.uploadCompressedTextureFromByteArray(ETC1Data, 0); + result = ETC1; + } catch(e:Error) { + result = NONE; + } + } + testTexture.dispose(); + return result; + } + + public static function vectorNumberToByteArray(vector:Vector.):ByteArray { + var result:ByteArray = new ByteArray(); + result.endian = Endian.LITTLE_ENDIAN; + for (var i:int = 0; i < vector.length; i++) { + result.writeFloat(vector[i]); + } + result.position = 0; + return result; + } + + public static function byteArrayToVectorUint(byteArray:ByteArray):Vector. { + var result:Vector. = new Vector.(); + var length:uint = 0; + byteArray.position = 0; + byteArray.endian = Endian.LITTLE_ENDIAN; + while (byteArray.bytesAvailable > 0) { + result[length++] = byteArray.readUnsignedShort(); + } + return result; + } + + public static function createVertexBufferFromByteArray(context:Context3D, byteArray:ByteArray, numVertices:uint, stride:uint = 3):VertexBuffer3D { + if (context == null) { + throw new ReferenceError("context is not set"); + } + var buffer:VertexBuffer3D = context.createVertexBuffer(numVertices, stride); + buffer.uploadFromByteArray(byteArray, 0, 0, numVertices); + return buffer; + } + + public static function createVertexBufferFromVector(context:Context3D, vector:Vector., numVertices:uint, stride:uint = 3):VertexBuffer3D { + if (context == null) { + throw new ReferenceError("context is not set"); + } + var buffer:VertexBuffer3D = context.createVertexBuffer(numVertices, stride); + + var byteArray:ByteArray = A3DUtils.vectorNumberToByteArray(vector); + buffer.uploadFromByteArray(byteArray, 0, 0, numVertices); + return buffer; + } + + public static function createTextureFromByteArray(context:Context3D, byteArray:ByteArray, width:Number, height:Number, format:String):Texture { + if (context == null) { + throw new ReferenceError("context is not set"); + } + var texture:Texture = context.createTexture(width, height, format, false); + texture.uploadCompressedTextureFromByteArray(byteArray, 0); + + return texture; + } + + public static function createIndexBufferFromByteArray(context:Context3D, byteArray:ByteArray, numIndices:uint):IndexBuffer3D { + if (context == null) { + throw new ReferenceError("context is not set"); + } + var buffer:IndexBuffer3D = context.createIndexBuffer(numIndices); + buffer.uploadFromByteArray(byteArray, 0, 0, numIndices); + + return buffer; + } + + public static function createIndexBufferFromVector(context:Context3D, vector:Vector., numIndices:int = -1):IndexBuffer3D { + if (context == null) { + throw new ReferenceError("context is not set"); + } + var count:uint = numIndices > 0 ? numIndices : vector.length; + var buffer:IndexBuffer3D = context.createIndexBuffer(count); + buffer.uploadFromVector(vector, 0, count); + + var byteArray:ByteArray = new ByteArray(); + byteArray.endian = Endian.LITTLE_ENDIAN; + for (var i:int = 0; i < count; i++) { + byteArray.writeInt(vector[i]); + } + byteArray.position = 0; + + buffer.uploadFromVector(vector, 0, count); + + return buffer; + } + + // Disassembler + private static var programType:Vector. = Vector.(["VERTEX", "FRAGMENT"]); + private static var samplerDimension:Vector. = Vector.(["2D", "cube", "3D"]); + private static var samplerWraping:Vector. = Vector.(["clamp", "repeat"]); + private static var samplerMipmap:Vector. = Vector.(["mipnone", "mipnearest", "miplinear"]); + private static var samplerFilter:Vector. = Vector.(["nearest", "linear"]); + private static var swizzleType:Vector. = Vector.(["x", "y", "z", "w"]); + private static var twoOperandsCommands:Dictionary; + + // TODO: option to turn off auto-prefixes + public static function disassemble(byteCode:ByteArray):String { + if (!twoOperandsCommands) { + twoOperandsCommands = new Dictionary(); + twoOperandsCommands[0x1] = true; + twoOperandsCommands[0x2] = true; + twoOperandsCommands[0x3] = true; + twoOperandsCommands[0x4] = true; + twoOperandsCommands[0x6] = true; + twoOperandsCommands[0xb] = true; + twoOperandsCommands[0x11] = true; + twoOperandsCommands[0x12] = true; + twoOperandsCommands[0x13] = true; + twoOperandsCommands[0x17] = true; + twoOperandsCommands[0x18] = true; + twoOperandsCommands[0x19] = true; + twoOperandsCommands[0x26] = true; + twoOperandsCommands[0x28] = true; + twoOperandsCommands[0x29] = true; + twoOperandsCommands[0x2a] = true; + twoOperandsCommands[0x2c] = true; + twoOperandsCommands[0x2d] = true; + } + var res:String = ""; + byteCode.position = 0; + if (byteCode.bytesAvailable < 7) { + return "error in byteCode header"; + } + + res += "magic = " + byteCode.readUnsignedByte().toString(16); + res += "\nversion = " + byteCode.readInt().toString(10); + res += "\nshadertypeid = " + byteCode.readUnsignedByte().toString(16); + var pType:String = programType[byteCode.readByte()]; + res += "\nshadertype = " + pType; + res += "\nsource\n"; + pType = pType.substring(0, 1).toLowerCase(); + var lineNumber:uint = 1; + while (byteCode.bytesAvailable - 24 >= 0) { + res += (lineNumber++).toString() + ": " + getCommand(byteCode, pType) + "\n"; + } + if (byteCode.bytesAvailable > 0) { + res += "\nunexpected byteCode length. extra bytes:" + byteCode.bytesAvailable; + } + return res; + } + + private static function getCommand(byteCode:ByteArray, programType:String):String { + var cmd:uint = byteCode.readUnsignedInt(); + var command:String = CommandType.COMMAND_NAMES[cmd]; + var result:String; + var destNumber:uint = byteCode.readUnsignedShort(); + var swizzle:uint = byteCode.readByte(); + var s:String = ""; + var destSwizzle:uint = 4; + if (swizzle < 15) { + s += "."; + s += ((swizzle & 0x1) > 0) ? "x" : ""; + s += ((swizzle & 0x2) > 0) ? "y" : ""; + s += ((swizzle & 0x4) > 0) ? "z" : ""; + s += ((swizzle & 0x8) > 0) ? "w" : ""; + destSwizzle = s.length - 1; + } + + var sourceSwizzleLimit:int = destSwizzle; + if (cmd == CommandType.TEX) { + sourceSwizzleLimit = 2; + } else if (cmd == CommandType.DP3) { + sourceSwizzleLimit = 3; + } else if (cmd == CommandType.DP4) { + sourceSwizzleLimit = 4; + } + + var destType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); + result = command + " " + attachProgramPrefix(destType, programType) + destNumber.toString() + s + ", "; + result += attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); + + if (twoOperandsCommands[cmd]) { + if (cmd == CommandType.TEX || cmd == CommandType.TED) { + result += ", " + attachProgramPrefix(getSamplerVariable(byteCode), programType); + } else { + result += ", " + attachProgramPrefix(getSourceVariable(byteCode, sourceSwizzleLimit), programType); + } + } else { + byteCode.readDouble(); + } + + if (cmd == CommandType.ELS || cmd == CommandType.EIF) { + result = " " + command; + } + return result; + } + + private static function attachProgramPrefix(variable:String, programType:String):String { + var char:uint = variable.charCodeAt(0); + if (char == "o".charCodeAt(0)) { + return variable + (programType == "f" ? "c" : "p"); + } else if (char == "d".charCodeAt(0)) { + return "o"+variable; + } else if (char != "v".charCodeAt(0)) { + return programType + variable; + } + return variable; + } + + private static function getSamplerVariable(byteCode:ByteArray):String { + var number:uint = byteCode.readUnsignedInt(); + byteCode.readByte(); + var dim:uint = byteCode.readByte() >> 4; + var wraping:uint = byteCode.readByte() >> 4; + var n:uint = byteCode.readByte(); + return "s" + number.toString() + " <" + samplerDimension[dim] + ", " + samplerWraping[wraping] + + ", " + samplerFilter[(n >> 4) & 0xf] + ", " + samplerMipmap[n & 0xf] + ">"; + } + + private static function getSourceVariable(byteCode:ByteArray, swizzleLimit:uint):String { + var s1Number:uint = byteCode.readUnsignedShort(); + var offset:uint = byteCode.readUnsignedByte(); + var s:String = getSourceSwizzle(byteCode.readUnsignedByte(), swizzleLimit); + + var s1Type:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); + var indexType:String = VariableType.TYPE_NAMES[byteCode.readUnsignedByte()].charAt(0); + var comp:String = swizzleType[byteCode.readUnsignedByte()]; + + if (byteCode.readUnsignedByte() > 0) { + return s1Type + "[" + indexType + s1Number.toString() + "." + comp + ((offset > 0) ? ("+" + offset.toString()) : "") + "]" + s; + } + return s1Type + s1Number.toString() + s; + } + + private static function getSourceSwizzle(swizzle:uint, swizzleLimit:uint = 4):String { + var s:String = ""; + if (swizzle != 0xe4) { + s += "."; + s += swizzleType[(swizzle & 0x3)]; + s += swizzleType[(swizzle >> 2) & 0x3]; + s += swizzleType[(swizzle >> 4) & 0x3]; + s += swizzleType[(swizzle >> 6) & 0x3]; + s = swizzleLimit < 4 ? s.substring(0, swizzleLimit + 1) : s; + } + return s; + } + + alternativa3d static function checkParent(child:Class, parent:Class):Boolean { + var current:Class = child; + if (parent == null) return true; + while (true) { + if (current == parent) return true; + var className:String = getQualifiedSuperclassName(current); + if (className != null) { + current = getDefinitionByName(className) as Class; + } else return false; + } + return false; + } + + } +} diff --git a/src/alternativa/engine3d/materials/compiler/CommandType.as b/src/alternativa/engine3d/materials/compiler/CommandType.as index cd74482..324ff80 100644 --- a/src/alternativa/engine3d/materials/compiler/CommandType.as +++ b/src/alternativa/engine3d/materials/compiler/CommandType.as @@ -1,148 +1,148 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ -package alternativa.engine3d.materials.compiler { - import flash.utils.Dictionary; - - /** - * @private - */ - public class CommandType { - 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 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"; - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ +package alternativa.engine3d.materials.compiler { + + + /** + * @private + */ + public class CommandType { + 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 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 : Array = []; + 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"; + } +} diff --git a/src/alternativa/engine3d/materials/compiler/DestinationVariable.as b/src/alternativa/engine3d/materials/compiler/DestinationVariable.as index c2bd655..c65fc70 100644 --- a/src/alternativa/engine3d/materials/compiler/DestinationVariable.as +++ b/src/alternativa/engine3d/materials/compiler/DestinationVariable.as @@ -1,74 +1,74 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ - -package alternativa.engine3d.materials.compiler { - - import flash.utils.ByteArray; - - /** - * @private - */ - public class DestinationVariable extends Variable { - - public function DestinationVariable(source:String) { - var strType : String = source.match(/[tovid]/)[0]; - index = parseInt(source.match(/\d+/)[0], 10); - var swizzle:Array = source.match(/\.[xyzw]{1,4}/); - var regmask:uint; - var maskmatch:String = swizzle ? swizzle[0] : null; - if (maskmatch != null) { - regmask = 0; - var cv:int; - var maskLength:uint = maskmatch.length; - // If first char is point, then skip - for (var i:int = 1; i < maskLength; i++) { - cv = maskmatch.charCodeAt(i) - X_CHAR_CODE; - if (cv == -1) cv = 3; - regmask |= 1 << cv; - } - } else { - regmask = 0xf; - // id swizzle or mask - } - lowerCode = (regmask << 16) | index; - - switch(strType){ - case "t": - lowerCode |= 0x2000000; - type = 2; - break; - case "o": - lowerCode |= 0x3000000; - type = 3; - break; - case "v": - lowerCode |= 0x4000000; - type = 4; - break; - case "d": - lowerCode |= 0x6000000; - type = 6; - break; - case "i": - lowerCode |= 0x7000000; - type = 7; - break; - default : - throw new ArgumentError("Wrong destination register type, must be \"t\" or \"o\" or \"v\", var = " + source); - break; - } - } - - override public function writeToByteArray(byteCode:ByteArray, newIndex:int, newType:int, offset:int = 0):void { - byteCode.position = position + offset; - - byteCode.writeUnsignedInt((lowerCode & ~(0xf00ffff)) | newIndex | (newType << 24)); - } - - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ + +package alternativa.engine3d.materials.compiler { + + import flash.utils.ByteArray; + + /** + * @private + */ + public class DestinationVariable extends Variable { + + public function DestinationVariable(source:String) { + var strType : String = source.match(/[tovid]/)[0]; + index = parseInt(source.match(/\d+/)[0], 10); + var swizzle:Array = source.match(/\.[xyzw]{1,4}/); + var regmask:uint; + var maskmatch:String = swizzle ? swizzle[0] : null; + if (maskmatch != null) { + regmask = 0; + var cv:int; + var maskLength:uint = maskmatch.length; + // If first char is point, then skip + for (var i:int = 1; i < maskLength; i++) { + cv = maskmatch.charCodeAt(i) - X_CHAR_CODE; + if (cv == -1) cv = 3; + regmask |= 1 << cv; + } + } else { + regmask = 0xf; + // id swizzle or mask + } + lowerCode = (regmask << 16) | index; + + switch(strType){ + case "t": + lowerCode |= 0x2000000; + type = VariableType.TEMPORARY; + break; + case "o": + lowerCode |= 0x3000000; + type = VariableType.OUTPUT; + break; + case "v": + lowerCode |= 0x4000000; + type = VariableType.VARYING; + break; + case "d": + lowerCode |= 0x6000000; + type = VariableType.DEPTH; + break; + case "i": + lowerCode |= 0x7000000; + type = VariableType.INPUT; + break; + default : + throw new ArgumentError('Wrong destination register type, must be "t" or "o" or "v" or "d", var = ' + source); + break; + } + } + + override public function writeToByteArray(byteCode:ByteArray, newIndex:int, newType:int, offset:int = 0):void { + byteCode.position = position + offset; + + byteCode.writeUnsignedInt((lowerCode & ~(0xf00ffff)) | newIndex | (newType << 24)); + } + + } +} diff --git a/src/alternativa/engine3d/materials/compiler/Linker.as b/src/alternativa/engine3d/materials/compiler/Linker.as index bd16d72..983d1db 100644 --- a/src/alternativa/engine3d/materials/compiler/Linker.as +++ b/src/alternativa/engine3d/materials/compiler/Linker.as @@ -1,426 +1,426 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ - -package alternativa.engine3d.materials.compiler { - - import alternativa.engine3d.alternativa3d; - - import flash.display3D.Context3DProgramType; - import flash.utils.ByteArray; - import flash.utils.Dictionary; - import flash.utils.Endian; - - use namespace alternativa3d; - - /** - * @private - * Dynamic shader linker - */ - public class Linker { - - /** - * Data after linking. - */ - public var data:ByteArray = null; - - /** - * Number of used slots. - */ - public var slotsCount:int = 0; - /** - * Number of lines of the shader code. - */ - public var commandsCount:int = 0; - - /** - * Linker type. Can be vertex of fragment. - */ - public var type:String; - - private var procedures:Vector. = new Vector.(); - - /** - * @private - * Variables after linking. - */ - alternativa3d var _linkedVariables:Object; - - // Dictionary of temporary variables at this linker. Key is a name of variable, value is a variable. - private var _localVariables:Object = new Object(); - - // Key - procedure, value - array of strings. - private var _inputParams:Dictionary = new Dictionary(); - // Key - procedure, value - array of strings. - private var _outputParams:Dictionary = new Dictionary(); - - // Counters of variables by types - private var _locals:Vector. = new Vector.(7, true); - - private var samplers:Object = new Object(); - - private var _varyings:Object = new Object(); - - /** - * Creates a new Linker instance. - * - * @param programType Type of shader. - */ - public function Linker(programType:String) { - type = programType; - } - - /** - * Clears a content. - */ - public function clear():void { - data = null; - _locals[0] = _locals[1] = _locals[2] = _locals[3] = _locals[4] = _locals[5] = _locals[6] = 0; - procedures.length = 0; - _varyings = new Object(); - samplers = new Object(); - - commandsCount = 0; - slotsCount = 0; - _linkedVariables = null; - - _inputParams = new Dictionary(); - _outputParams = new Dictionary(); - } - - /** - * Adds a new shader procedure. - * - * @param procedure Procedure to add. - * - * @see Procedure - */ - public function addProcedure(procedure:Procedure, ...args):void { - for each(var v:Variable in procedure.variablesUsages[VariableType.VARYING]) { - if (v == null) continue; - var nv:Variable = _varyings[v.name] = new Variable(); - nv.name = v.name; - nv.type = v.type; - nv.index = -1; - } - procedures.push(procedure); - _inputParams[procedure] = args; - data = null; - } - - /** - * Declaration of variable of given type. - * - * @param name Name of variable - * @param type Type of variable. Should be one of the VariableType constants. The default value is Temporary variable. - * - * @see VariableType - */ - public function declareVariable(name:String, type:uint = 2):void { - var v:Variable = new Variable(); - v.index = -1; - v.type = type; - v.name = name; - _localVariables[name] = v; - if (v.type == VariableType.VARYING) { - _varyings[v.name] = v; - } - data = null; - } - - public function declareSampler(output:String, uv:String, sampler:String, options:String):void { - if (_localVariables[uv] == null) { - throw new ArgumentError("Undefined variable " + uv); - } - - if (_localVariables[sampler] == null) { - throw new ArgumentError("Undefined variable " + sampler); - } - - if (_localVariables[output] == null) { - declareVariable(output, 2); - } - data = null; - } - - /** - * Setting of input parameters of procedure. - * - * @param procedure A procedure to which parameters will be set. - * @param args Names of variables, separated by the comma, that are passed into the procedure. - * Variables must be previously declared, using the method declareVariable(). - * - * @see #declareVariable() - */ - public function setInputParams(procedure:Procedure, ...args):void { - _inputParams[procedure] = args; - data = null; - } - - /** - * Setting of output parameters of procedure. - * - * @param procedure A procedure to which parameters will be set. - * @param args Names of variables, separated by the comma, that are passed into the procedure. - * Variables must be previously declared, using the method declareVariable(). - * - * @see #declareVariable() - */ - public function setOutputParams(procedure:Procedure, ...args):void { - _outputParams[procedure] = args; - data = null; - } - - /** - * Returns of index of variable after the linking. - * - * @param name Name of variable. - * @return Its index for sending to Context3D - */ - public function getVariableIndex(name:String):int { - if (_linkedVariables == null) throw new Error("Not linked"); - var variable:Variable = _linkedVariables[name]; - if (variable == null) { - throw new Error('Variable "' + name + '" not found'); - } - return variable.index; - } - - /** - * Returns index of variable or -1 there is no variable with such name. - */ - public function findVariable(name:String):int { - if (_linkedVariables == null) throw new Error("Has not linked"); - var variable:Variable = _linkedVariables[name]; - if (variable == null) { - return -1; - } - return variable.index; - } - - /** - * Returns the existence of this variable in linked code. - * @param name Name of variable - */ - public function containsVariable(name:String):Boolean { - if (_linkedVariables == null) throw new Error("Not linked"); - return _linkedVariables[name] != null; - } - - /** - * Linking of procedures to one shader. - */ - public function link(version:uint = 1):void { - if (data != null) return; - - var v:Variable; - var variables:Object = _linkedVariables = new Object(); - var p:Procedure; - var i:int, j:int; - var nv:Variable; - for each (v in _localVariables) { - nv = variables[v.name] = new Variable(); - nv.index = -1; - nv.type = v.type; - nv.name = v.name; - nv.size = v.size; - } - data = new ByteArray(); - data.endian = Endian.LITTLE_ENDIAN; - data.writeByte(0xa0); - // tag version - 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 - - commandsCount = 0; - slotsCount = 0; - - _locals[0] = 0; - _locals[1] = 0; - _locals[2] = 0; - _locals[3] = 0; - _locals[4] = 0; - _locals[5] = 0; - _locals[6] = 0; - // First iteration - collecting of variables. - for each (p in procedures) { - _locals[1] += p.reservedConstants; - var iLength:int = p.variablesUsages.length; - for (i = 0; i < iLength; i++) { - var vector:Vector. = p.variablesUsages[i]; - var jLength:int = vector.length; - for (j = 0; j < jLength; j++) { - v = vector[j]; - if (v == null || v.name == null) continue; - 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()); - } - nv = variables[v.name] = new Variable(); - nv.index = -1; - nv.type = v.type; - nv.name = v.name; - nv.size = v.size; - } - } - } - - for each (p in procedures) { - // Changing of inputs - var offset:int = data.length; - data.position = data.length; - data.writeBytes(p.byteCode, 0, p.byteCode.length); - var input:Array = _inputParams[p]; - var output:Array = _outputParams[p]; - var param:String; - var numParams:int; - if (input != null) { - numParams = input.length; - for (j = 0; j < numParams; j++) { - param = input[j]; - v = variables[param]; - if (v == null) { - throw new Error("Input parameter not set. paramName = " + param); - } - if (p.variablesUsages[7].length > j) { - var inParam:Variable = p.variablesUsages[7][j]; - if (inParam == null) { - throw new Error("Input parameter set, but not exist in code. paramName = " + param + ", register = i" + j.toString()); - } - if (v.index < 0) { - v.index = _locals[v.type]; - _locals[v.type] += v.size; - } - while (inParam != null) { - inParam.writeToByteArray(data, v.index, v.type, offset); - inParam = inParam.next; - } - } - - } - } - if (output != null) { - // Output parameters - numParams = output.length; - for (j = 0; j < numParams; j++) { - param = output[j]; - v = variables[param]; - if (v == null) { - if (j == 0 && (i == procedures.length - 1)) { - // Output variable - continue; - } - throw new Error("Output parameter have not declared. paramName = " + param); - } - if (v.index < 0) { - if (v.type != 2) { - throw new Error("Wrong output type:" + VariableType.TYPE_NAMES[v.type]); - } - v.index = _locals[v.type]; - _locals[v.type] += v.size; - } - var outParam:Variable = p.variablesUsages[3][j]; - if (outParam == null) { - throw new Error("Output parameter set, but not exist in code. paramName = " + param + ", register = i" + j.toString()); - } - while (outParam != null) { - outParam.writeToByteArray(data, v.index, v.type, offset); - outParam = outParam.next; - } - } - } - var vars:Vector. = p.variablesUsages[2]; - for (j = 0; j < vars.length; j++) { - v = vars[j]; - if (v == null) continue; - while (v != null) { - v.writeToByteArray(data, v.index + _locals[2], VariableType.TEMPORARY, offset); - v = v.next; - } - } - - resolveVariablesUsages(data, variables, p.variablesUsages[0], VariableType.ATTRIBUTE, offset); - resolveVariablesUsages(data, variables, p.variablesUsages[1], VariableType.CONSTANT, offset); - resolveVariablesUsages(data, _varyings, p.variablesUsages[4], VariableType.VARYING, offset); - resolveVariablesUsages(data, variables, p.variablesUsages[5], VariableType.SAMPLER, offset); - - commandsCount += p.commandsCount; - slotsCount += p.slotsCount; - } - } - - private function resolveVariablesUsages(code:ByteArray, variables:Object, variableUsages:Vector., type:uint, offset:int):void { - for (var j:int = 0; j < variableUsages.length; j++) { - var vUsage:Variable = variableUsages[j]; - if (vUsage == null) continue; - if (vUsage.isRelative) continue; - var variable:Variable = variables[vUsage.name]; - if (variable.index < 0) { - variable.index = _locals[type]; - _locals[type] += variable.size; - } - while (vUsage != null) { - vUsage.writeToByteArray(code, variable.index, variable.type, offset); - vUsage = vUsage.next; - } - } - } - - /** - * Returns description of procedures: name, size, input and output parameters. - * @return - */ - public function describeLinkageInfo():String { - var str:String; - var result:String = "LINKER:\n"; - var totalCodes:uint = 0; - var totalCommands:uint = 0; - for (var i:int = 0; i < procedures.length; i++) { - var p:Procedure = procedures[i]; - if (p.name != null) { - result += p.name + "("; - } else { - result += "#" + i.toString() + "("; - } - var args:* = _inputParams[p]; - if (args != null) { - for each (str in args) { - result += str + ","; - } - result = result.substr(0, result.length - 1); - } - result += ")"; - args = _outputParams[p]; - if (args != null) { - result += "->("; - for each (str in args) { - result += str + ","; - } - result = result.substr(0, result.length - 1); - result += ")"; - } - result += " [IS:" + p.slotsCount.toString() + ", CMDS:" + p.commandsCount.toString() + "]\n"; - totalCodes += p.slotsCount; - totalCommands += p.commandsCount; - } - result += "[IS:" + totalCodes.toString() + ", CMDS:" + totalCommands.toString() + "]\n"; - return result; - } - - public function get varyings():Object { - return _varyings; - } - - public function set varyings(value:Object):void { - _varyings = value; - data = null; - } - - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ + +package alternativa.engine3d.materials.compiler { + + import alternativa.engine3d.alternativa3d; + + import flash.display3D.Context3DProgramType; + import flash.utils.ByteArray; + import flash.utils.Dictionary; + import flash.utils.Endian; + + use namespace alternativa3d; + + /** + * @private + * Dynamic shader linker + */ + public class Linker { + + /** + * Data after linking. + */ + public var data:ByteArray = null; + + /** + * Number of used slots. + */ + public var slotsCount:int = 0; + /** + * Number of lines of the shader code. + */ + public var commandsCount:int = 0; + + /** + * Linker type. Can be vertex of fragment. + */ + public var type:String; + + private var procedures:Vector. = new Vector.(); + + /** + * @private + * Variables after linking. + */ + alternativa3d var _linkedVariables:Object; + + // Dictionary of temporary variables at this linker. Key is a name of variable, value is a variable. + private var _localVariables:Object = {}; + + // Key - procedure, value - array of strings. + private var _inputParams:Dictionary = new Dictionary(); + // Key - procedure, value - array of strings. + private var _outputParams:Dictionary = new Dictionary(); + + // Counters of variables by types + private var _locals:Vector. = new Vector.(7, true); + + private var samplers:Object = {}; + + private var _varyings:Object = {}; + + /** + * Creates a new Linker instance. + * + * @param programType Type of shader. + */ + public function Linker(programType:String) { + type = programType; + } + + /** + * Clears a content. + */ + public function clear():void { + data = null; + _locals[0] = _locals[1] = _locals[2] = _locals[3] = _locals[4] = _locals[5] = _locals[6] = 0; + procedures.length = 0; + _varyings = {}; + samplers = {}; + + commandsCount = 0; + slotsCount = 0; + _linkedVariables = null; + + _inputParams = new Dictionary(); + _outputParams = new Dictionary(); + } + + /** + * Adds a new shader procedure. + * + * @param procedure Procedure to add. + * + * @see Procedure + */ + public function addProcedure(procedure:Procedure, ...args):void { + for each(var v:Variable in procedure.variablesUsages[VariableType.VARYING]) { + if (v == null) continue; + var nv:Variable = _varyings[v.name] = new Variable(); + nv.name = v.name; + nv.type = v.type; + nv.index = -1; + } + procedures.push(procedure); + _inputParams[procedure] = args; + data = null; + } + + /** + * Declaration of variable of given type. + * + * @param name Name of variable + * @param type Type of variable. Should be one of the VariableType constants. The default value is Temporary variable. + * + * @see VariableType + */ + public function declareVariable(name:String, type:uint = 2):void { + var v:Variable = new Variable(); + v.index = -1; + v.type = type; + v.name = name; + _localVariables[name] = v; + if (v.type == VariableType.VARYING) { + _varyings[v.name] = v; + } + data = null; + } + + public function declareSampler(output:String, uv:String, sampler:String, options:String):void { + if (_localVariables[uv] == null) { + throw new ArgumentError("Undefined variable " + uv); + } + + if (_localVariables[sampler] == null) { + throw new ArgumentError("Undefined variable " + sampler); + } + + if (_localVariables[output] == null) { + declareVariable(output, 2); + } + data = null; + } + + /** + * Setting of input parameters of procedure. + * + * @param procedure A procedure to which parameters will be set. + * @param args Names of variables, separated by the comma, that are passed into the procedure. + * Variables must be previously declared, using the method declareVariable(). + * + * @see #declareVariable() + */ + public function setInputParams(procedure:Procedure, ...args):void { + _inputParams[procedure] = args; + data = null; + } + + /** + * Setting of output parameters of procedure. + * + * @param procedure A procedure to which parameters will be set. + * @param args Names of variables, separated by the comma, that are passed into the procedure. + * Variables must be previously declared, using the method declareVariable(). + * + * @see #declareVariable() + */ + public function setOutputParams(procedure:Procedure, ...args):void { + _outputParams[procedure] = args; + data = null; + } + + /** + * Returns of index of variable after the linking. + * + * @param name Name of variable. + * @return Its index for sending to Context3D + */ + public function getVariableIndex(name:String):int { + if (_linkedVariables == null) throw new Error("Not linked"); + var variable:Variable = _linkedVariables[name]; + if (variable == null) { + throw new Error('Variable "' + name + '" not found'); + } + return variable.index; + } + + /** + * Returns index of variable or -1 there is no variable with such name. + */ + public function findVariable(name:String):int { + if (_linkedVariables == null) throw new Error("Has not linked"); + var variable:Variable = _linkedVariables[name]; + if (variable == null) { + return -1; + } + return variable.index; + } + + /** + * Returns the existence of this variable in linked code. + * @param name Name of variable + */ + public function containsVariable(name:String):Boolean { + if (_linkedVariables == null) throw new Error("Not linked"); + return _linkedVariables[name] != null; + } + + /** + * Linking of procedures to one shader. + */ + public function link(version:uint = 1):void { + if (data != null) return; + + var v:Variable; + var variables:Object = _linkedVariables = {}; + var p:Procedure; + var i:int, j:int; + var nv:Variable; + for each (v in _localVariables) { + nv = variables[v.name] = new Variable(); + nv.index = -1; + nv.type = v.type; + nv.name = v.name; + nv.size = v.size; + } + data = new ByteArray(); + data.endian = Endian.LITTLE_ENDIAN; + data.writeByte(0xa0); + // tag version + 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 + + commandsCount = 0; + slotsCount = 0; + + _locals[0] = 0; + _locals[1] = 0; + _locals[2] = 0; + _locals[3] = 0; + _locals[4] = 0; + _locals[5] = 0; + _locals[6] = 0; + // First iteration - collecting of variables. + for each (p in procedures) { + _locals[1] += p.reservedConstants; + var iLength:int = p.variablesUsages.length; + for (i = 0; i < iLength; i++) { + var vector:Vector. = p.variablesUsages[i]; + var jLength:int = vector.length; + for (j = 0; j < jLength; j++) { + v = vector[j]; + if (v == null || v.name == null) continue; + if (v.name == null && i != 2 && i != 3 && i != 6 && i != 7) { + // TODO: Never happens + throw new Error("Linkage error: Noname variable. Procedure = " + p.name + ", type = " + i.toString() + ", index = " + j.toString()); + } + nv = variables[v.name] = new Variable(); + nv.index = -1; + nv.type = v.type; + nv.name = v.name; + nv.size = v.size; + } + } + } + + for each (p in procedures) { + // Changing of inputs + var offset:int = data.length; + data.position = data.length; + data.writeBytes(p.byteCode, 0, p.byteCode.length); + var input:Array = _inputParams[p]; + var output:Array = _outputParams[p]; + var param:String; + var numParams:int; + if (input != null) { + numParams = input.length; + for (j = 0; j < numParams; j++) { + param = input[j]; + v = variables[param]; + if (v == null) { + throw new Error("Input parameter not set. paramName = " + param); + } + if (p.variablesUsages[7].length > j) { + var inParam:Variable = p.variablesUsages[7][j]; + if (inParam == null) { + throw new Error("Input parameter set, but not used in code. paramName = " + param + ", register = i" + j.toString()); + } + if (v.index < 0) { + v.index = _locals[v.type]; + _locals[v.type] += v.size; + } + while (inParam != null) { + inParam.writeToByteArray(data, v.index, v.type, offset); + inParam = inParam.next; + } + } + } + } + if (output != null) { + // Output parameters + numParams = output.length; + for (j = 0; j < numParams; j++) { + param = output[j]; + v = variables[param]; + if (v == null) { + if (j == 0 && (i == procedures.length - 1)) { + // Output variable + continue; + } + throw new Error("Output parameter not declared. paramName = " + param); + } + if (v.index < 0) { + if (v.type != 2) { + throw new Error("Wrong output type:" + VariableType.TYPE_NAMES[v.type]); + } + v.index = _locals[v.type]; + _locals[v.type] += v.size; + } + var outParam:Variable = p.variablesUsages[3][j]; + if (outParam == null) { + throw new Error("Output parameter set, but not exist in code. paramName = " + param + ", register = i" + j.toString()); + } + while (outParam != null) { + outParam.writeToByteArray(data, v.index, v.type, offset); + outParam = outParam.next; + } + } + } + var vars:Vector. = p.variablesUsages[2]; + for (j = 0; j < vars.length; j++) { + v = vars[j]; + if (v == null) continue; + while (v != null) { + v.writeToByteArray(data, _locals[2] + v.index, VariableType.TEMPORARY, offset); + v = v.next; + } + } + + resolveVariablesUsages(data, variables, p.variablesUsages[0], VariableType.ATTRIBUTE, offset); + resolveVariablesUsages(data, variables, p.variablesUsages[1], VariableType.CONSTANT, offset); + resolveVariablesUsages(data, _varyings, p.variablesUsages[4], VariableType.VARYING, offset); + resolveVariablesUsages(data, variables, p.variablesUsages[5], VariableType.SAMPLER, offset); + + commandsCount += p.commandsCount; + slotsCount += p.slotsCount; + } + } + + private function resolveVariablesUsages(code:ByteArray, variables:Object, variableUsages:Vector., type:uint, offset:int):void { + for (var j:int = 0; j < variableUsages.length; j++) { + var vUsage:Variable = variableUsages[j]; + if (vUsage == null) continue; + if (vUsage.isRelative) continue; + var variable:Variable = variables[vUsage.name]; + if (variable.index < 0) { + variable.index = _locals[type]; + _locals[type] += variable.size; + } + while (vUsage != null) { + vUsage.writeToByteArray(code, variable.index, variable.type, offset); + vUsage = vUsage.next; + } + } + } + + /** + * Returns description of procedures: name, size, input and output parameters. + * @return + */ + public function describeLinkageInfo():String { + var str:String; + var result:String = "LINKER:\n"; + var totalCodes:uint = 0; + var totalCommands:uint = 0; + for (var i:int = 0; i < procedures.length; i++) { + var p:Procedure = procedures[i]; + if (p.name != null) { + result += p.name + "("; + } else { + result += "#" + i.toString() + "("; + } + var args:* = _inputParams[p]; + if (args != null) { + for each (str in args) { + result += str + ","; + } + result = result.substr(0, result.length - 1); + } + result += ")"; + args = _outputParams[p]; + if (args != null) { + result += "->("; + for each (str in args) { + result += str + ","; + } + result = result.substr(0, result.length - 1); + result += ")"; + } + result += " [IS:" + p.slotsCount.toString() + ", CMDS:" + p.commandsCount.toString() + "]\n"; + totalCodes += p.slotsCount; + totalCommands += p.commandsCount; + } + result += "[IS:" + totalCodes.toString() + ", CMDS:" + totalCommands.toString() + "]\n"; + return result; + } + + public function get varyings():Object { + return _varyings; + } + + public function set varyings(value:Object):void { + _varyings = value; + data = null; + } + + } +} diff --git a/src/alternativa/engine3d/materials/compiler/Procedure.as b/src/alternativa/engine3d/materials/compiler/Procedure.as index acb3a6b..3609450 100644 --- a/src/alternativa/engine3d/materials/compiler/Procedure.as +++ b/src/alternativa/engine3d/materials/compiler/Procedure.as @@ -1,544 +1,541 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ -package alternativa.engine3d.materials.compiler { - import alternativa.engine3d.alternativa3d; - - import flash.display3D.Context3DProgramType; - import flash.utils.ByteArray; - import flash.utils.Endian; - - use namespace alternativa3d; - /** - * @private - * Shader procedure - */ - public class Procedure { - // Name of procedure - public var name : String; - - /** - * @private - */ - alternativa3d static const crc32Table : Vector. = createCRC32Table(); - - private static function createCRC32Table() : Vector. { - var crc_table : Vector. = new Vector.(256); - var crc : uint, i : int, j : int; - for (i = 0; i < 256; i++) { - crc = i; - for (j = 0; j < 8; j++) - crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320 : crc >> 1; - - crc_table[i] = crc; - } - return crc_table; - } - - /** - * @private - */ - alternativa3d var crc32 : uint = 0; - - /** - * Code of procedure. - */ - public var byteCode : ByteArray = new ByteArray(); - - public var variablesUsages : Vector.> = new Vector.>(); - - /** - * Number of instruction slots in a procedure. - */ - public var slotsCount : int = 0; - - /** - * Number of strings in a procedure. - */ - public var commandsCount : int = 0; - - /** - * @private - */ - alternativa3d var reservedConstants : uint = 0; - - /** - * Creates a new Procedure instance. - * - * @param array Array of AGAL strings - */ - public function Procedure(array : Array = null, name : String = null) { - byteCode.endian = Endian.LITTLE_ENDIAN; - this.name = name; - if (array != null) { - compileFromArray(array); - } - } - - public function getByteCode(type : String, version:uint = 1) : ByteArray { - var result : ByteArray = new ByteArray(); - result.endian = Endian.LITTLE_ENDIAN; - result.writeByte(0xa0); - result.writeUnsignedInt(version); - // AGAL version, big endian, bit pattern will be 0x01000000 - result.writeByte(0xa1); - // tag program id - result.writeByte((type == Context3DProgramType.FRAGMENT) ? 1 : 0); - // vertex or fragment - result.writeBytes(byteCode); - return result; - } - - private function addVariableUsage(v : Variable) : void { - var vars : Vector. = variablesUsages[v.type]; - var index : int = v.index; - if (index >= vars.length) { - vars.length = index + 1; - } else { - v.next = vars[index]; - } - vars[index] = v; - } - - /** - * Sets name and size of variable - * - * @param type Type of variable. One of VariableType constants. - * @param index Index of variable at shader code. - * @param name Assigned variable name. - * @param size Size of variable in vectors. - * - * @see VariableType - */ - public function assignVariableName(type : uint, index : uint, name : String, size : uint = 1) : void { - var v : Variable = variablesUsages[type][index]; - while (v != null) { - v.size = size; - v.name = name; - v = v.next; - } - } - - /** - * Compiles shader from the string. - */ - public function compileFromString(source : String) : void { - var commands : Array = source.split("\n"); - compileFromArray(commands); - } - - /** - * Compiles shader from the array of strings. - */ - public function compileFromArray(source : Array) : void { - for (var i : int = 0; i < 8; i++) { - variablesUsages[i] = new Vector.(); - } - byteCode.length = 0; - commandsCount = 0; - slotsCount = 0; - - const decPattern : RegExp = /# *[acvs]\d{1,3} *= *[a-zA-Z0-9_]*/i; - var declarationStrings : Vector. = new Vector.(); - var count : int = source.length; - for (i = 0; i < count; i++) { - var cmd : String = source[i]; - var declaration : Array = cmd.match(decPattern); - if (declaration != null && declaration.length > 0) { - declarationStrings.push(declaration[0]); - } else { - writeAGALExpression(cmd); - } - } - for (i = 0,count = declarationStrings.length; i < count; i++) { - var decArray : Array = declarationStrings[i].split("="); - var regType : String = decArray[0].match(/[acvs]/i); - var varIndex : int = int(decArray[0].match(/\d{1,3}/i)); - var varName : String = decArray[1].match(/[a-zA-Z0-9]*/i); - switch (regType.toLowerCase()) { - case "a": - assignVariableName(VariableType.ATTRIBUTE, varIndex, varName); - break; - case "c": - assignVariableName(VariableType.CONSTANT, varIndex, varName); - break; - case "v": - assignVariableName(VariableType.VARYING, varIndex, varName); - break; - case "s": - assignVariableName(VariableType.SAMPLER, varIndex, varName); - break; - } - } - crc32 = createCRC32(byteCode); - } - - public function assignConstantsArray(registersCount : uint = 1) : void { - reservedConstants = registersCount; - } - - 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) { - source = source.substr(0, commentIndex); - } - // Errors: - // 1) Merged commands - // 2) Syntax errors - // -- incorrect number of operands - // -- unknown commands - // -- unknown registers - // -- unknown constructions - // 3) Using of unwritable registers - // -- in vertex shader (va0, c0, s0); - // -- in fragment shader (v0, va0, c0, s0); - // 4) Using of unreadable registers - // -- in vertex shader (v0, s0); - // -- in fragment shader (va0); - // 5) Deny write into the input registers - // 6) Mismatch the size of types of registers - // 7) Relative addressing in the fragment shader is not possible - // -- You can not use it for recording - // -- Offset is out of range [0..255] - // 8) Flow errors - // -- unused variable - // -- using of uninitialized variable - // -- using of partially uninitialized variable - // -- function is not return value - // 9) Restrictions - // -- too many commands - // -- too many constants - // -- too many textures - // -- too many temporary variables - // -- too many interpolated values - // You can not use kil in fragment shader - - var operands : Array = source.match(agalParser); - - // It is possible not use the input parameter. It is optimization of the linker - // Determine the size of constant - - var opCode : String = operands[0]; - var destination : DestinationVariable; - var source1 : SourceVariable; - var source2 : Variable; - if (opCode == "kil" || opCode == "ife" || opCode == "ine" || opCode == "ifg" || opCode == "ifl") {//no dist - source1 = new SourceVariable(operands[1]); - addVariableUsage(source1); - } else if (opCode == "els" || opCode == "eif") { // no dist no sources - source1 = null; - source2 = null; - } else { - destination = new DestinationVariable(operands[1]); - addVariableUsage(destination); - source1 = new SourceVariable(operands[2]); - addVariableUsage(source1); - } - var type : uint; - switch (opCode) { - case "mov": - type = CommandType.MOV; - slotsCount++; - break; - case "add": - type = CommandType.ADD; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "sub": - type = CommandType.SUB; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "mul": - type = CommandType.MUL; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "div": - type = CommandType.DIV; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "rcp": - type = CommandType.RCP; - slotsCount++; - break; - case "min": - type = CommandType.MIN; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "max": - type = CommandType.MAX; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "frc": - type = CommandType.FRC; - slotsCount++; - break; - case "sqt": - type = CommandType.SQT; - slotsCount++; - break; - case "rsq": - type = CommandType.RSQ; - slotsCount++; - break; - case "pow": - type = CommandType.POW; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount += 3; - break; - case "log": - type = CommandType.LOG; - slotsCount++; - break; - case "exp": - type = CommandType.EXP; - slotsCount++; - break; - case "nrm": - type = CommandType.NRM; - slotsCount += 3; - break; - case "sin": - type = CommandType.SIN; - slotsCount += 8; - break; - case "cos": - type = CommandType.COS; - slotsCount += 8; - break; - case "crs": - type = CommandType.CRS; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount += 2; - break; - case "dp3": - type = CommandType.DP3; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "dp4": - type = CommandType.DP4; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "abs": - type = CommandType.ABS; - slotsCount++; - break; - case "neg": - type = CommandType.NEG; - slotsCount++; - break; - case "sat": - type = CommandType.SAT; - slotsCount++; - break; - case "m33": - type = CommandType.M33; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount += 3; - break; - case "m44": - type = CommandType.M44; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount += 4; - break; - case "m34": - type = CommandType.M34; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount += 3; - 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": - type = CommandType.KIL; - slotsCount++; - break; - case "tex": - type = CommandType.TEX; - source2 = new SamplerVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "sge": - type = CommandType.SGE; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "slt": - type = CommandType.SLT; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "sgn": - type = CommandType.SGN; - slotsCount++; - break; - case "seq": - type = CommandType.SEQ; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - case "sne": - type = CommandType.SNE; - source2 = new SourceVariable(operands[3]); - addVariableUsage(source2); - slotsCount++; - break; - default: - // TODO: throw error - unknown command - break; - } - - - // Fill of byteCode of command - byteCode.writeUnsignedInt(type); - if (destination != null) { - destination.position = byteCode.position; - byteCode.writeUnsignedInt(destination.lowerCode); - } else { - byteCode.writeUnsignedInt(0); - } - if (source1 != null) { - source1.position = byteCode.position; - if (source1.relative != null) { - addVariableUsage(source1.relative); - source1.relative.position = byteCode.position; - } - byteCode.writeUnsignedInt(source1.lowerCode); - byteCode.writeUnsignedInt(source1.upperCode); - } else { - byteCode.position = (byteCode.length += 8); - } - if (source2 != null) { - source2.position = byteCode.position; - var s2v : SourceVariable = source2 as SourceVariable; - if (s2v != null && s2v.relative != null) { - addVariableUsage(s2v.relative); - s2v.relative.position = s2v.position; - } - byteCode.writeUnsignedInt(source2.lowerCode); - byteCode.writeUnsignedInt(source2.upperCode); - } else { - byteCode.position = (byteCode.length += 8); - } - commandsCount++; - } - - /** - * Creates and returns an instance of procedure from array of strings. - */ - public static function compileFromArray(source : Array, name : String = null) : Procedure { - var proc : Procedure = new Procedure(source, name); - return proc; - } - - /** - * Creates and returns an instance of procedure from string. - */ - public static function compileFromString(source : String, name : String = null) : Procedure { - var proc : Procedure = new Procedure(null, name); - proc.compileFromString(source); - return proc; - } - - /** - * Create an instance of procedure. - */ - public function newInstance() : Procedure { - var res : Procedure = new Procedure(); - res.byteCode = this.byteCode; - res.variablesUsages = this.variablesUsages; - res.slotsCount = this.slotsCount; - res.reservedConstants = this.reservedConstants; - res.commandsCount = this.commandsCount; - res.name = name; - return res; - } - - /** - * @private - */ - alternativa3d static function createCRC32(byteCode : ByteArray) : uint { - byteCode.position = 0; - var len : uint = byteCode.length; - var crc : uint = 0xFFFFFFFF; - while (len--) { - var byte : int = byteCode.readByte(); - crc = crc32Table[(crc ^ byte) & 0xFF] ^ (crc >> 8); - } - return crc ^ 0xFFFFFFFF; - } - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ +package alternativa.engine3d.materials.compiler { + + import alternativa.engine3d.alternativa3d; + + import flash.display3D.Context3DProgramType; + import flash.utils.ByteArray; + import flash.utils.Endian; + + use namespace alternativa3d; + /** + * @private + * Shader procedure + */ + public class Procedure { + // Name of procedure + public var name:String; + + /** + * @private + */ + alternativa3d static const crc32Table:Vector. = createCRC32Table(); + + private static function createCRC32Table():Vector. { + var crc_table:Vector. = new Vector.(256); + var crc:uint, i:int, j:int; + for (i = 0; i < 256; i++) { + crc = i; + for (j = 0; j < 8; j++) + crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320:crc >> 1; + + crc_table[i] = crc; + } + return crc_table; + } + + /** + * @private + */ + alternativa3d var crc32:uint = 0; + + /** + * Code of procedure. + */ + public var byteCode:ByteArray = new ByteArray(); + + public var variablesUsages:Vector.> = new Vector.>(); + + /** + * Number of instruction slots in a procedure. + */ + public var slotsCount:int = 0; + + /** + * Number of strings in a procedure. + */ + public var commandsCount:int = 0; + + /** + * @private + */ + alternativa3d var reservedConstants:uint = 0; + + /** + * Creates a new Procedure instance. + * + * @param array Array of AGAL strings + */ + public function Procedure(array:Array = null, name:String = null) { + byteCode.endian = Endian.LITTLE_ENDIAN; + this.name = name; + if (array != null) { + compileFromArray(array); + } + } + + public function getByteCode(type:String, version:uint = 1):ByteArray { + var result:ByteArray = new ByteArray(); + result.endian = Endian.LITTLE_ENDIAN; + result.writeByte(0xa0); + result.writeUnsignedInt(version); + // AGAL version, big endian, bit pattern will be 0x01000000 + result.writeByte(0xa1); + // tag program id + result.writeByte((type == Context3DProgramType.FRAGMENT) ? 1:0); + // vertex or fragment + result.writeBytes(byteCode); + return result; + } + + private function addVariableUsage(v:Variable):void { + var vars:Vector. = variablesUsages[v.type]; + var index:int = v.index; + if (index >= vars.length) { + vars.length = index + 1; + } else { + v.next = vars[index]; + } + vars[index] = v; + } + + /** + * Sets name and size of variable + * + * @param type Type of variable. One of VariableType constants. + * @param index Index of variable at shader code. + * @param name Assigned variable name. + * @param size Size of variable in vectors. + * + * @see VariableType + */ + public function assignVariableName(type:uint, index:uint, name:String, size:uint = 1):void { + var v:Variable = variablesUsages[type][index]; + while (v != null) { + v.size = size; + v.name = name; + v = v.next; + } + } + + /** + * Compiles shader from the string. + */ + public function compileFromString(source:String):void { + var commands:Array = source.split("\n"); + compileFromArray(commands); + } + + /** + * Compiles shader from the array of strings. + */ + public function compileFromArray(source:Array):void { + for (var i:int = 0; i < 8; i++) { + variablesUsages[i] = new Vector.(); + } + byteCode.length = 0; + commandsCount = 0; + slotsCount = 0; + + const decPattern:RegExp = /# *[acvs]\d{1,3} *= *[a-zA-Z0-9_]*/i; + var declarationStrings:Vector. = new Vector.(); + var count:int = source.length; + for (i = 0; i < count; i++) { + var cmd:String = source[i]; + var declaration:Array = cmd.match(decPattern); + if (declaration != null && declaration.length > 0) { + declarationStrings.push(declaration[0]); + } else { + writeAGALExpression(cmd); + } + } + for (i = 0,count = declarationStrings.length; i < count; i++) { + var decArray:Array = declarationStrings[i].split("="); + var regType:String = decArray[0].match(/[acvs]/i); + var varIndex:int = int(decArray[0].match(/\d{1,3}/i)); + var varName:String = decArray[1].match(/[a-zA-Z0-9]*/i); + switch (regType.toLowerCase()) { + case "a": + assignVariableName(VariableType.ATTRIBUTE, varIndex, varName); + break; + case "c": + assignVariableName(VariableType.CONSTANT, varIndex, varName); + break; + case "v": + assignVariableName(VariableType.VARYING, varIndex, varName); + break; + case "s": + assignVariableName(VariableType.SAMPLER, varIndex, varName); + break; + } + } + crc32 = createCRC32(byteCode); + } + + public function assignConstantsArray(registersCount:uint = 1):void { + reservedConstants = registersCount; + } + + 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) { + source = source.substr(0, commentIndex); + } + // Errors: + // 1) Merged commands + // 2) Syntax errors + // -- incorrect number of operands + // -- unknown commands + // -- unknown registers + // -- unknown constructions + // 3) Using of unwritable registers + // -- in vertex shader (va0, c0, s0); + // -- in fragment shader (v0, va0, c0, s0); + // 4) Using of unreadable registers + // -- in vertex shader (v0, s0); + // -- in fragment shader (va0); + // 5) Deny write into the input registers + // 6) Mismatch the size of types of registers + // 7) Relative addressing in the fragment shader is not possible + // -- You can not use it for recording + // -- Offset is out of range [0..255] + // 8) Flow errors + // -- unused variable + // -- using of uninitialized variable + // -- using of partially uninitialized variable + // -- function is not return value + // 9) Restrictions + // -- too many commands + // -- too many constants + // -- too many textures + // -- too many temporary variables + // -- too many interpolated values + // You can not use kil in fragment shader + + var operands:Array = source.match(agalParser); + + var opCode:String = operands[0]; + var destination:DestinationVariable; + var source1:SourceVariable; + var source2:Variable; + if (opCode == "kil" || opCode == "ife" || opCode == "ine" || opCode == "ifg" || opCode == "ifl") {//no dist + source1 = new SourceVariable(operands[1]); + addVariableUsage(source1); + } else if (opCode == "els" || opCode == "eif") { // no dist no sources + source1 = null; + source2 = null; + } else { + destination = new DestinationVariable(operands[1]); + addVariableUsage(destination); + source1 = new SourceVariable(operands[2]); + addVariableUsage(source1); + } + var type:uint; + switch (opCode) { + case "mov": + type = CommandType.MOV; + slotsCount++; + break; + case "add": + type = CommandType.ADD; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "sub": + type = CommandType.SUB; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "mul": + type = CommandType.MUL; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "div": + type = CommandType.DIV; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "rcp": + type = CommandType.RCP; + slotsCount++; + break; + case "min": + type = CommandType.MIN; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "max": + type = CommandType.MAX; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "frc": + type = CommandType.FRC; + slotsCount++; + break; + case "sqt": + type = CommandType.SQT; + slotsCount++; + break; + case "rsq": + type = CommandType.RSQ; + slotsCount++; + break; + case "pow": + type = CommandType.POW; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount += 3; + break; + case "log": + type = CommandType.LOG; + slotsCount++; + break; + case "exp": + type = CommandType.EXP; + slotsCount++; + break; + case "nrm": + type = CommandType.NRM; + slotsCount += 3; + break; + case "sin": + type = CommandType.SIN; + slotsCount += 8; + break; + case "cos": + type = CommandType.COS; + slotsCount += 8; + break; + case "crs": + type = CommandType.CRS; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount += 2; + break; + case "dp3": + type = CommandType.DP3; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "dp4": + type = CommandType.DP4; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "abs": + type = CommandType.ABS; + slotsCount++; + break; + case "neg": + type = CommandType.NEG; + slotsCount++; + break; + case "sat": + type = CommandType.SAT; + slotsCount++; + break; + case "m33": + type = CommandType.M33; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount += 3; + break; + case "m44": + type = CommandType.M44; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount += 4; + break; + case "m34": + type = CommandType.M34; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount += 3; + 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": + type = CommandType.KIL; + slotsCount++; + break; + case "tex": + type = CommandType.TEX; + source2 = new SamplerVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "sge": + type = CommandType.SGE; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "slt": + type = CommandType.SLT; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "sgn": + type = CommandType.SGN; + slotsCount++; + break; + case "seq": + type = CommandType.SEQ; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + case "sne": + type = CommandType.SNE; + source2 = new SourceVariable(operands[3]); + addVariableUsage(source2); + slotsCount++; + break; + default: + // TODO: throw error - unknown command + break; + } + + // Fill of byteCode of command + byteCode.writeUnsignedInt(type); + if (destination != null) { + destination.position = byteCode.position; + byteCode.writeUnsignedInt(destination.lowerCode); + } else { + byteCode.writeUnsignedInt(0); + } + if (source1 != null) { + source1.position = byteCode.position; + if (source1.relative != null) { + addVariableUsage(source1.relative); + source1.relative.position = byteCode.position; + } + byteCode.writeUnsignedInt(source1.lowerCode); + byteCode.writeUnsignedInt(source1.upperCode); + } else { + byteCode.position = (byteCode.length += 8); + } + if (source2 != null) { + source2.position = byteCode.position; + var s2v:SourceVariable = source2 as SourceVariable; + if (s2v != null && s2v.relative != null) { + addVariableUsage(s2v.relative); + s2v.relative.position = s2v.position; + } + byteCode.writeUnsignedInt(source2.lowerCode); + byteCode.writeUnsignedInt(source2.upperCode); + } else { + byteCode.position = (byteCode.length += 8); + } + commandsCount++; + } + + /** + * Creates and returns an instance of procedure from array of strings. + */ + public static function compileFromArray(source:Array, name:String = null):Procedure { + var proc:Procedure = new Procedure(source, name); + return proc; + } + + /** + * Creates and returns an instance of procedure from string. + */ + public static function compileFromString(source:String, name:String = null):Procedure { + var proc:Procedure = new Procedure(null, name); + proc.compileFromString(source); + return proc; + } + + /** + * Create an instance of procedure. + */ + public function newInstance():Procedure { + var res:Procedure = new Procedure(); + res.byteCode = this.byteCode; + res.variablesUsages = this.variablesUsages; + res.slotsCount = this.slotsCount; + res.reservedConstants = this.reservedConstants; + res.commandsCount = this.commandsCount; + res.name = name; + return res; + } + + /** + * @private + */ + alternativa3d static function createCRC32(byteCode:ByteArray):uint { + byteCode.position = 0; + var len:uint = byteCode.length; + var crc:uint = 0xFFFFFFFF; + while (len--) { + var byte:int = byteCode.readByte(); + crc = crc32Table[(crc ^ byte) & 0xFF] ^ (crc >> 8); + } + return crc ^ 0xFFFFFFFF; + } + } +} diff --git a/src/alternativa/engine3d/materials/compiler/SourceVariable.as b/src/alternativa/engine3d/materials/compiler/SourceVariable.as index 5b9c829..251b401 100644 --- a/src/alternativa/engine3d/materials/compiler/SourceVariable.as +++ b/src/alternativa/engine3d/materials/compiler/SourceVariable.as @@ -1,103 +1,102 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. - * You may add additional accurate notices of copyright ownership. - * - * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ - * */ -package alternativa.engine3d.materials.compiler { - import flash.utils.ByteArray; - - /** - * @private - */ - public class SourceVariable extends Variable { - public var relative : RelativeVariable; - - override public function get size() : uint { - if (relative) { - return 0; - } - return super.size; - } - - public function SourceVariable(source : String) { - var strType : String = String(source.match(/[catsoivd]/g)[0]); - - var regmask : uint; - - var relreg : Array = source.match(/\[.*\]/g); - var isRel : Boolean = relreg.length > 0; - if (isRel) { - source = source.replace(relreg[0], "0"); - } else { - index = parseInt(source.match(/\d+/g)[0], 10); - } - - var swizzle : Array = source.match(/\.[xyzw]{1,4}/); - - var maskmatch : String = swizzle ? swizzle[0] : null; - if (maskmatch) { - regmask = 0; - var cv : int; - var maskLength : uint = maskmatch.length; - for (var i : int = 1; i < maskLength; i++) { - cv = maskmatch.charCodeAt(i) - X_CHAR_CODE; - if (cv == -1) cv = 3; - regmask |= cv << ( ( i - 1 ) << 1 ); - } - for ( ; i <= 4; i++ ) - regmask |= cv << ( ( i - 1 ) << 1 ); - // repeat last - } else { - regmask = 0xe4; - // id swizzle or mask - } - lowerCode = (regmask << 24) | index; - - switch(strType) { - case "a": - type = VariableType.ATTRIBUTE; - break; - case "c": - type = VariableType.CONSTANT; - break; - case "t": - type = VariableType.TEMPORARY; - break; - case "o": - type = VariableType.OUTPUT; - break; - case "v": - type = VariableType.VARYING; - break; - case "i": - type = VariableType.INPUT; - break; - case "d": - type = VariableType.DEPTH; - break; - default : - 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; - } - upperCode = type; - if (isRel) { - relative = new RelativeVariable(relreg[0]); - lowerCode |= relative.lowerCode; - upperCode |= relative.upperCode; - isRelative = true; - } - } - - override public function writeToByteArray(byteCode : ByteArray, newIndex : int, newType : int, offset : int = 0) : void { - if (relative == null) { - super.writeToByteArray(byteCode, newIndex, newType, offset); - } else { - byteCode.position = position + 2; - } - byteCode.position = position + offset + 4; - byteCode.writeByte(newType); - } - } -} +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + * You may add additional accurate notices of copyright ownership. + * + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ + * */ +package alternativa.engine3d.materials.compiler { + + import flash.utils.ByteArray; + + /** + * @private + */ + public class SourceVariable extends Variable { + public var relative:RelativeVariable; + + override public function get size():uint { + if (relative) { + return 0; + } + return super.size; + } + + public function SourceVariable(source:String) { + var strType:String = String(source.match(/[catsoiv]/g)[0]); + + var regmask:uint; + + var relreg:Array = source.match(/\[.*\]/g); + var isRel:Boolean = relreg.length > 0; + if (isRel) { + source = source.replace(relreg[0], "0"); + } else { + index = parseInt(source.match(/\d+/g)[0], 10); + } + + var swizzle:Array = source.match(/\.[xyzw]{1,4}/); + + var maskmatch:String = swizzle ? swizzle[0]:null; + if (maskmatch) { + regmask = 0; + var cv:int; + var maskLength:uint = maskmatch.length; + for (var i:int = 1; i < maskLength; i++) { + cv = maskmatch.charCodeAt(i) - X_CHAR_CODE; + if (cv == -1) cv = 3; + regmask |= cv << ( ( i - 1 ) << 1 ); + } + for ( ; i <= 4; i++ ) + regmask |= cv << ( ( i - 1 ) << 1 ); + // repeat last + } else { + regmask = 0xe4; + // id swizzle or mask + } + lowerCode = (regmask << 24) | index; + + switch(strType) { + case "a": + type = VariableType.ATTRIBUTE; + break; + case "c": + type = VariableType.CONSTANT; + break; + case "t": + type = VariableType.TEMPORARY; + break; + case "o": + type = VariableType.OUTPUT; + break; + case "v": + type = VariableType.VARYING; + break; + case "i": + type = VariableType.INPUT; + break; + default : + throw new ArgumentError('Wrong source register type, must be "a" or "c" or "t" or "o" or "v" or "i", var = ' + source); + break; + } + upperCode = type; + if (isRel) { + relative = new RelativeVariable(relreg[0]); + lowerCode |= relative.lowerCode; + upperCode |= relative.upperCode; + isRelative = true; + } + } + + override public function writeToByteArray(byteCode:ByteArray, newIndex:int, newType:int, offset:int = 0):void { + if (relative == null) { + super.writeToByteArray(byteCode, newIndex, newType, offset); + } else { + byteCode.position = position + 2; + } + byteCode.position = position + offset + 4; + byteCode.writeByte(newType); + } + + } +}