UNPKG

@awayjs/renderer

Version:
896 lines (895 loc) 43.3 kB
import { Matrix3D, ArgumentError, UUID, AbstractionSet, } from '@awayjs/core'; import { AGALMiniAssembler, ContextGLBlendFactor, ContextGLBlendEquation, ContextGLCompareMode, ContextGLTriangleFace, BlendMode, ShaderRegisterCache, ShaderRegisterData, } from '@awayjs/stage'; /** * ShaderBase keeps track of the number of dependencies for "named registers" used across a pass. * Named registers are that are not necessarily limited to a single method. They are created by the compiler and * passed on to methods. The compiler uses the results to reserve usages through RegisterPool, which can be removed * each time a method has been compiled into the shader. * * @see RegisterPool.addUsage */ var ShaderBase = /** @class */ (function () { /** * Creates a new MethodCompilerVO object. */ function ShaderBase(renderElements, renderMaterial, pass, stage) { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ZERO ]; this._blendEquation = [ ContextGLBlendEquation.ADD, ContextGLBlendEquation.ADD ]; /* private _blendFactorSource: ContextGLBlendFactor = ContextGLBlendFactor.ONE; private _blendFactorDest: ContextGLBlendFactor = ContextGLBlendFactor.ZERO; */ this._invalidProgram = true; this._animationVertexCode = ''; this._animationFragmentCode = ''; this._vertexCode = ''; this._fragmentCode = ''; this._postAnimationFragmentCode = ''; this.usesBlending = false; this.useImageRect = false; this.usesCurves = false; /** * The depth compare mode used to render the renderables using this material. * * @see away.stagegl.ContextGLCompareMode */ this.depthCompareMode = ContextGLCompareMode.LESS_EQUAL; /** * Indicate whether the shader should write to the depth buffer or not. Ignored when blending is enabled. */ this.writeDepth = true; this._defaultCulling = ContextGLTriangleFace.BACK; this._pInverseSceneMatrix = new Float32Array(16); //set ambient values to default this.ambientR = 0xFF; this.ambientG = 0xFF; this.ambientB = 0xFF; /** * Indicates whether there are any dependencies on the world-space position vector. */ this.usesGlobalPosFragment = false; /** * Indicates whether there are any dependencies on the local position vector. */ this.usesPositionFragment = false; /** * */ this.imageIndices = new Array(); this.id = UUID.Next(); this.abstractions = new AbstractionSet(this); this._renderElements = renderElements; this._renderMaterial = renderMaterial; this._pass = pass; this._stage = stage; this._view = renderElements.renderer.view; this.profile = this._stage.profile; } Object.defineProperty(ShaderBase.prototype, "view", { get: function () { return this._view; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "stage", { get: function () { return this._stage; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "pass", { get: function () { return this._pass; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "renderMaterial", { get: function () { return this._renderMaterial; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "programData", { get: function () { if (this._invalidProgram) this._updateProgram(); return this._programData; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "usesAnimation", { get: function () { return this._usesAnimation; }, set: function (value) { if (this._usesAnimation == value) return; this._usesAnimation = value; this.invalidateProgram(); }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "numUsedVertexConstants", { get: function () { if (this._invalidProgram) this._updateProgram(); return this._numUsedVertexConstants; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "numUsedFragmentConstants", { get: function () { if (this._invalidProgram) this._updateProgram(); return this._numUsedFragmentConstants; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "numUsedStreams", { /** * The amount of used vertex streams in the vertex code. * Used by the animation code generation to know from which index on streams are available. */ get: function () { if (this._invalidProgram) this._updateProgram(); return this._numUsedStreams; }, enumerable: false, configurable: true }); Object.defineProperty(ShaderBase.prototype, "numUsedTextures", { /** * */ get: function () { if (this._invalidProgram) this._updateProgram(); return this._numUsedTextures; }, enumerable: false, configurable: true }); ShaderBase.prototype.requestAbstraction = function (asset) { var store = ShaderBase._store[asset.assetType]; return store.length ? store.pop() : new ShaderBase._abstractionClassPool[asset.assetType]; }; ShaderBase.prototype.storeAbstraction = function (abstraction, assetType) { ShaderBase._store[assetType].push(abstraction); }; /** * * @param imageObjectClass */ ShaderBase.registerAbstraction = function (abstractionClass, assetClass) { ShaderBase._abstractionClassPool[assetClass.assetType] = abstractionClass; ShaderBase._store[assetClass.assetType] = []; }; ShaderBase.prototype._includeDependencies = function () { this._renderMaterial.renderElements._includeDependencies(this); this._pass._includeDependencies(this); //this.usesCommonData = this.usesCurves || this.usesCommonData; }; /** * Clears dependency counts for all registers. Called when recompiling a pass. */ ShaderBase.prototype.reset = function () { this.projectionDependencies = 0; this.normalDependencies = 0; this.colorDependencies = 0; this.viewDirDependencies = 0; this.uvDependencies = 0; this.secondaryUVDependencies = 0; this.globalPosDependencies = 0; this.tangentDependencies = 0; this.usesCommonData = false; this.usesGlobalPosFragment = false; this.usesPositionFragment = false; this.usesFragmentAnimation = false; this.usesTangentSpace = false; this.outputsNormals = false; this.outputsTangentNormals = false; }; /** * The blend mode to use when drawing this renderable. The following blend modes are supported: * <ul> * <li>BlendMode.NORMAL: No blending, unless the material inherently needs it</li> * <li>BlendMode.LAYER: Force blending. * This will draw the object the same as NORMAL, but without writing depth writes.</li> * <li>BlendMode.MULTIPLY</li> * <li>BlendMode.ADD</li> * <li>BlendMode.ALPHA</li> * </ul> */ ShaderBase.prototype.setBlendMode = function (value) { this.usesBlending = true; this.usesPremultipliedAlpha = true; // reset blend equation onto ADD, ADD this._blendEquation = [0, 0]; //ADD switch (value) { case BlendMode.NORMAL: { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ZERO ]; this.usesBlending = false; this.usesPremultipliedAlpha = false; break; } case BlendMode.LAYER: { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE_MINUS_SOURCE_ALPHA ]; break; } case BlendMode.MULTIPLY: { this._blendFactor = [ ContextGLBlendFactor.DESTINATION_COLOR, ContextGLBlendFactor.ONE_MINUS_SOURCE_ALPHA, ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE_MINUS_SOURCE_ALPHA ]; break; } case BlendMode.ADD: { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE ]; break; } case BlendMode.SCREEN: { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE_MINUS_SOURCE_COLOR, ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE_MINUS_SOURCE_ALPHA ]; break; } case BlendMode.SUBTRACT: { this._blendFactor = [ ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE, ContextGLBlendFactor.ONE ]; this._blendEquation = [ ContextGLBlendEquation.SUBTRACT, ContextGLBlendEquation.ADD ]; break; } case BlendMode.ALPHA: { this._blendFactor = [ContextGLBlendFactor.ZERO, ContextGLBlendFactor.SOURCE_ALPHA]; this.usesPremultipliedAlpha = false; break; } case BlendMode.ERASE: { this._blendFactor = [ContextGLBlendFactor.ZERO, ContextGLBlendFactor.ONE_MINUS_SOURCE_ALPHA]; this.usesPremultipliedAlpha = false; break; } default: { throw new ArgumentError("Unsupported blend mode: ".concat(value)); } } }; /** * @inheritDoc */ ShaderBase.prototype._activate = function () { if (!this.programData.program) { this.programData.program = this._stage.context.createProgram(); var vertexPart = (new AGALMiniAssembler() .assemble('part vertex 1\n' + this.programData.vertexString + 'endpart')).vertex; var fragmentPart = (new AGALMiniAssembler() .assemble('part fragment 1\n' + this.programData.fragmentString + 'endpart')).fragment; //@ts-ignore this.programData.program.upload(vertexPart, fragmentPart); } //set program data this._stage.context.setProgram(this.programData.program); this._stage.context.setCulling(this.useBothSides ? ContextGLTriangleFace.NONE : this._defaultCulling, this._view.projection.coordinateSystem); if (!this.usesTangentSpace && this.cameraPositionIndex >= 0) { var pos = this._view.projection.transform.matrix3D.position; this.vertexConstantData[this.cameraPositionIndex] = pos.x; this.vertexConstantData[this.cameraPositionIndex + 1] = pos.y; this.vertexConstantData[this.cameraPositionIndex + 2] = pos.z; } this._stage.context.setDepthTest((this.writeDepth && !this.usesBlending), this.depthCompareMode); //@ts-ignore this._stage.context.setBlendEquation(this._blendEquation[0], this._blendEquation[1]); //@ts-ignore this._stage.context.setBlendFactors(this._blendFactor[0], this._blendFactor[1], // MUST be undef for non-separated mode this._blendFactor[2], this._blendFactor[3]); this.activeElements = null; }; /** * @inheritDoc */ ShaderBase.prototype._deactivate = function () { //For the love of god don't remove this if you want your multi-material shadows to not flicker like shit this._stage.context.setDepthTest(true, ContextGLCompareMode.LESS_EQUAL); this.activeElements = null; }; /** * * * @param renderable * @param stage * @param camera */ ShaderBase.prototype._setRenderState = function (renderState) { var node = renderState.entity.node; if (node.container.animator) node.container.animator.setRenderState(this, renderState); var rawData; if (this.usesUVTransform) { var uvMatrix = renderState.uvMatrix; if (uvMatrix) { //transpose rawData = uvMatrix.rawData; this.vertexConstantData[this.uvMatrixIndex] = rawData[0]; this.vertexConstantData[this.uvMatrixIndex + 1] = rawData[2]; this.vertexConstantData[this.uvMatrixIndex + 3] = rawData[4]; this.vertexConstantData[this.uvMatrixIndex + 4] = rawData[1]; this.vertexConstantData[this.uvMatrixIndex + 5] = rawData[3]; this.vertexConstantData[this.uvMatrixIndex + 7] = rawData[5]; } else { this.vertexConstantData[this.uvMatrixIndex] = 1; this.vertexConstantData[this.uvMatrixIndex + 1] = 0; this.vertexConstantData[this.uvMatrixIndex + 3] = 0; this.vertexConstantData[this.uvMatrixIndex + 4] = 0; this.vertexConstantData[this.uvMatrixIndex + 5] = 1; this.vertexConstantData[this.uvMatrixIndex + 7] = 0; } } if (this.usesColorTransform) { var colorTransform = renderState.entity.colorTransform; if (colorTransform) { //TODO: AWDParser to write normalised color offsets rawData = colorTransform._rawData; this.fragmentConstantData[this.colorTransformIndex] = rawData[0]; this.fragmentConstantData[this.colorTransformIndex + 1] = rawData[1]; this.fragmentConstantData[this.colorTransformIndex + 2] = rawData[2]; this.fragmentConstantData[this.colorTransformIndex + 3] = rawData[3]; this.fragmentConstantData[this.colorTransformIndex + 4] = rawData[4] / 255; this.fragmentConstantData[this.colorTransformIndex + 5] = rawData[5] / 255; this.fragmentConstantData[this.colorTransformIndex + 6] = rawData[6] / 255; this.fragmentConstantData[this.colorTransformIndex + 7] = rawData[7] / 255; } else { this.fragmentConstantData[this.colorTransformIndex] = 1; this.fragmentConstantData[this.colorTransformIndex + 1] = 1; this.fragmentConstantData[this.colorTransformIndex + 2] = 1; this.fragmentConstantData[this.colorTransformIndex + 3] = 1; this.fragmentConstantData[this.colorTransformIndex + 4] = 0; this.fragmentConstantData[this.colorTransformIndex + 5] = 0; this.fragmentConstantData[this.colorTransformIndex + 6] = 0; this.fragmentConstantData[this.colorTransformIndex + 7] = 0; } } if (this.sceneNormalMatrixIndex >= 0) { this.sceneNormalMatrix.copyFrom(node.getInverseMatrix3D()); } if (this.usesTangentSpace && this.cameraPositionIndex >= 0) { node.getInverseMatrix3D().copyRawDataTo(this._pInverseSceneMatrix); var pos = this._view.projection.transform.matrix3D.position; var x = pos.x; var y = pos.y; var z = pos.z; this.vertexConstantData[this.cameraPositionIndex] = this._pInverseSceneMatrix[0] * x + this._pInverseSceneMatrix[4] * y + this._pInverseSceneMatrix[8] * z + this._pInverseSceneMatrix[12]; this.vertexConstantData[this.cameraPositionIndex + 1] = this._pInverseSceneMatrix[1] * x + this._pInverseSceneMatrix[5] * y + this._pInverseSceneMatrix[9] * z + this._pInverseSceneMatrix[13]; this.vertexConstantData[this.cameraPositionIndex + 2] = this._pInverseSceneMatrix[2] * x + this._pInverseSceneMatrix[6] * y + this._pInverseSceneMatrix[10] * z + this._pInverseSceneMatrix[14]; } }; ShaderBase.prototype.invalidateProgram = function () { this._invalidProgram = true; }; ShaderBase.prototype.dispose = function () { this._programData.dispose(); this._programData = null; this._registerCache.dispose(); this._registerCache = null; this._sharedRegisters = null; }; ShaderBase.prototype._updateProgram = function () { this._invalidProgram = false; this._sharedRegisters = new ShaderRegisterData(); this._registerCache = new ShaderRegisterCache(this.profile); this.reset(); this._includeDependencies(); this._initRegisterIndices(); this._compileDependencies(); //compile custom vertex & fragment codes from pass this._vertexCode += this._pass._getVertexCode(this._registerCache, this._sharedRegisters); this._fragmentCode += this._pass._getFragmentCode(this._registerCache, this._sharedRegisters); this._postAnimationFragmentCode += this._pass._getPostAnimationFragmentCode(this._registerCache, this._sharedRegisters); //check if alpha needs to be pre-multipled if (this.usesPremultipliedAlpha) { var target = this._sharedRegisters.shadedTarget; this._postAnimationFragmentCode += "mul ".concat(target, ".xyz, ").concat(target, ", ").concat(target, ".w\n"); } //assign the final output color to the output register this._postAnimationFragmentCode += "mov ".concat(this._registerCache.fragmentOutputRegister, ", ").concat(this._sharedRegisters.shadedTarget, "\n"); this._registerCache.removeFragmentTempUsage(this._sharedRegisters.shadedTarget); this._compileAnimationCode(); //initialise the required shader constants this._initConstantData(); var programData = this._stage.getProgramData(this._animationVertexCode + this._vertexCode, this._fragmentCode + this._animationFragmentCode + this._postAnimationFragmentCode); //check program data hasn't changed, keep count of program usages if (this._programData != programData) { if (this._programData) this._programData.dispose(); this._programData = programData; programData.usages++; } }; /** * Reset all the indices to "unused". */ ShaderBase.prototype._initRegisterIndices = function () { this.commonsDataIndex = -1; this.cameraPositionIndex = -1; this.curvesIndex = -1; this.uvIndex = -1; this.uvMatrixIndex = -1; this.colorTransformIndex = -1; this.secondaryUVIndex = -1; this.normalIndex = -1; this.colorBufferIndex = -1; this.tangentIndex = -1; this.sceneMatrixIndex = -1; this.sceneNormalMatrixIndex = -1; this.jointIndexIndex = -1; this.jointWeightIndex = -1; this.imageIndices.length = 0; this._sharedRegisters.animatedPosition = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(this._sharedRegisters.animatedPosition, 1); this._sharedRegisters.animatableAttributes.push(this._registerCache.getFreeVertexAttribute()); this._sharedRegisters.animationTargetRegisters.push(this._sharedRegisters.animatedPosition); this._vertexCode = ''; this._fragmentCode = ''; this._postAnimationFragmentCode = ''; //create commonly shared constant registers if (this.usesCommonData || this.normalDependencies > 0) { this._sharedRegisters.commons = this._registerCache.getFreeFragmentConstant(); this.commonsDataIndex = this._sharedRegisters.commons.index * 4; } //Creates the registers to contain the tangent data. //Needs to be created FIRST and in this order (for when using tangent space) if (this.tangentDependencies > 0 || this.outputsNormals) { this._sharedRegisters.tangentInput = this._registerCache.getFreeVertexAttribute(); this.tangentIndex = this._sharedRegisters.tangentInput.index; this._sharedRegisters.animatedTangent = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(this._sharedRegisters.animatedTangent, 1); if (this.usesTangentSpace) { this._sharedRegisters.bitangent = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(this._sharedRegisters.bitangent, 1); } this._sharedRegisters.animatableAttributes.push(this._sharedRegisters.tangentInput); this._sharedRegisters.animationTargetRegisters.push(this._sharedRegisters.animatedTangent); } if (this.normalDependencies > 0) { this._sharedRegisters.normalInput = this._registerCache.getFreeVertexAttribute(); this.normalIndex = this._sharedRegisters.normalInput.index; this._sharedRegisters.animatedNormal = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(this._sharedRegisters.animatedNormal, 1); this._sharedRegisters.animatableAttributes.push(this._sharedRegisters.normalInput); this._sharedRegisters.animationTargetRegisters.push(this._sharedRegisters.animatedNormal); } if (this.uvDependencies > 0) { this._sharedRegisters.uvInput = this._registerCache.getFreeVertexAttribute(); this.uvIndex = this._sharedRegisters.uvInput.index; if (!this.usesUVTransform) { this._sharedRegisters.animatedUV = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(this._sharedRegisters.animatedUV, 1); } } this._sharedRegisters.shadedTarget = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(this._sharedRegisters.shadedTarget, 1); }; /** * Compile the code for the methods. */ ShaderBase.prototype._compileDependencies = function () { if (this.colorDependencies > 0) { this._compileColorCode(); } //compile the world-space position if required if (this.globalPosDependencies > 0) this._compileGlobalPositionCode(); //compile the local-space position if required if (this.usesPositionFragment) this._compilePositionCode(); if (this.usesCurves) this._compileCurvesCode(); if (this.usesColorTransform) this._compileColorTransformCode(); if (this.secondaryUVDependencies > 0) this._compileSecondaryUVCode(); if (this.normalDependencies > 0) this._compileNormalCode(); if (this.viewDirDependencies > 0) this._compileViewDirCode(); //collect code from elements this._vertexCode += this._renderElements._getVertexCode(this, this._registerCache, this._sharedRegisters); this._fragmentCode += this._renderElements._getFragmentCode(this, this._registerCache, this._sharedRegisters); }; /** * Initializes the unchanging constant data for this shader object. */ ShaderBase.prototype._initConstantData = function () { var rc = this._registerCache; //Updates the amount of used register indices. var usedVC = this._numUsedVertexConstants = rc.numUsedVertexConstants; var usedFC = this._numUsedFragmentConstants = rc.numUsedFragmentConstants; this._numUsedStreams = rc.numUsedStreams; this._numUsedTextures = rc.numUsedTextures; if (!this.vertexConstantData || this.vertexConstantData.length !== usedVC * 4) this.vertexConstantData = new Float32Array(usedVC * 4); if (!this.fragmentConstantData || this.fragmentConstantData.length !== usedFC * 4) this.fragmentConstantData = new Float32Array(this._registerCache.numUsedFragmentConstants * 4); //Initialies viewMatrix if (this.viewMatrixIndex >= 0) { var data = new Float32Array(this.vertexConstantData.buffer, this.viewMatrixIndex * 4, 16); if (!this.viewMatrix) { this.viewMatrix = new Matrix3D(data); } else { this.viewMatrix._rawData = data; } } else if (this.viewMatrix) { this.viewMatrix = null; } //Initialies sceneMatrix if (this.sceneMatrixIndex >= 0) { var data = new Float32Array(this.vertexConstantData.buffer, this.sceneMatrixIndex * 4, 16); if (!this.sceneMatrix) { this.sceneMatrix = new Matrix3D(data); } else { this.sceneMatrix._rawData = data; } } else if (this.sceneMatrix) { this.sceneMatrix = null; } //Initializes commonly required constant values. if (this.commonsDataIndex >= 0) { this.fragmentConstantData[this.commonsDataIndex] = .5; this.fragmentConstantData[this.commonsDataIndex + 1] = 0; this.fragmentConstantData[this.commonsDataIndex + 2] = 1 / 255; this.fragmentConstantData[this.commonsDataIndex + 3] = 1; } //Initializes the default UV transformation matrix. if (this.uvMatrixIndex >= 0) { this.vertexConstantData[this.uvMatrixIndex] = 1; this.vertexConstantData[this.uvMatrixIndex + 1] = 0; this.vertexConstantData[this.uvMatrixIndex + 2] = 0; this.vertexConstantData[this.uvMatrixIndex + 3] = 0; this.vertexConstantData[this.uvMatrixIndex + 4] = 0; this.vertexConstantData[this.uvMatrixIndex + 5] = 1; this.vertexConstantData[this.uvMatrixIndex + 6] = 0; this.vertexConstantData[this.uvMatrixIndex + 7] = 0; } //Initializes the default colorTransform. if (this.colorTransformIndex >= 0) { this.fragmentConstantData[this.colorTransformIndex] = 1; this.fragmentConstantData[this.colorTransformIndex + 1] = 1; this.fragmentConstantData[this.colorTransformIndex + 2] = 1; this.fragmentConstantData[this.colorTransformIndex + 3] = 1; this.fragmentConstantData[this.colorTransformIndex + 4] = 0; this.fragmentConstantData[this.colorTransformIndex + 5] = 0; this.fragmentConstantData[this.colorTransformIndex + 6] = 0; this.fragmentConstantData[this.colorTransformIndex + 7] = 0; } if (this.sceneNormalMatrixIndex >= 0) { var data = new Float32Array(this.vertexConstantData.buffer, this.sceneNormalMatrixIndex * 4, 16); if (!this.sceneNormalMatrix) { this.sceneNormalMatrix = new Matrix3D(data); } else { this.sceneNormalMatrix._rawData = data; } } else if (this.sceneNormalMatrix) { this.sceneNormalMatrix = null; } if (this.cameraPositionIndex >= 0) this.vertexConstantData[this.cameraPositionIndex + 3] = 1; // init constant data in pass this._pass._initConstantData(); //init constant data in animation if (this._usesAnimation) this._renderMaterial.animationSet.doneAGALCode(this); }; ShaderBase.prototype._compileColorCode = function () { this._sharedRegisters.colorInput = this._registerCache.getFreeVertexAttribute(); this.colorBufferIndex = this._sharedRegisters.colorInput.index; this._sharedRegisters.colorVarying = this._registerCache.getFreeVarying(); this._vertexCode += "mov ".concat(this._sharedRegisters.colorVarying, ", ").concat(this._sharedRegisters.colorInput, "\n"); }; ShaderBase.prototype._compileGlobalPositionCode = function () { var temp = this._sharedRegisters.globalPositionVertex = this._registerCache.getFreeVertexVectorTemp(); this._registerCache.addVertexTempUsages(temp, this.globalPosDependencies); var sceneMatrixReg = this._registerCache.getFreeVertexConstant(); this._registerCache.getFreeVertexConstant(); this._registerCache.getFreeVertexConstant(); this._registerCache.getFreeVertexConstant(); this.sceneMatrixIndex = sceneMatrixReg.index * 4; var r = this._sharedRegisters; this._vertexCode += "m44 ".concat(r.globalPositionVertex, ", ").concat(r.animatedPosition, ", ").concat(sceneMatrixReg, "\n"); if (this.usesGlobalPosFragment) { r.globalPositionVarying = this._registerCache.getFreeVarying(); this._vertexCode += "mov ".concat(r.globalPositionVarying, ", ").concat(r.globalPositionVertex, "\n"); } }; ShaderBase.prototype._compilePositionCode = function () { var r = this._sharedRegisters; r.positionVarying = this._registerCache.getFreeVarying(); this._vertexCode += "mov ".concat(r.positionVarying, ", ").concat(r.animatedPosition, "\n"); }; ShaderBase.prototype._compileCurvesCode = function () { var r = this._sharedRegisters; r.curvesInput = this._registerCache.getFreeVertexAttribute(); this.curvesIndex = r.curvesInput.index; r.curvesVarying = this._registerCache.getFreeVarying(); this._vertexCode += 'mov ' + r.curvesVarying + ', ' + r.curvesInput + '\n'; var temp = this._registerCache.getFreeFragmentSingleTemp(); this._fragmentCode += 'mul ' + temp + ', ' + r.curvesVarying + '.y, ' + r.curvesVarying + '.y\n' + 'sub ' + temp + ', ' + temp + ', ' + r.curvesVarying + '.z\n' + 'mul ' + temp + ', ' + temp + ', ' + r.curvesVarying + '.x\n' + 'kil ' + temp + '\n'; }; /** * Calculate the transformed colours */ ShaderBase.prototype._compileColorTransformCode = function () { // rm, gm, bm, am - multiplier // ro, go, bo, ao - offset var ct1 = this._registerCache.getFreeFragmentConstant(); var ct2 = this._registerCache.getFreeFragmentConstant(); var target = this._sharedRegisters.shadedTarget; this.colorTransformIndex = ct1.index * 4; this._postAnimationFragmentCode += 'mul ' + target + ', ' + target + ', ' + ct1 + '\n'; this._postAnimationFragmentCode += 'add ' + target + ', ' + target + ', ' + ct2 + '\n'; }; /** * Provide the secondary UV coordinates. */ ShaderBase.prototype._compileSecondaryUVCode = function () { var uvAttributeReg = this._registerCache.getFreeVertexAttribute(); var r = this._sharedRegisters; this.secondaryUVIndex = uvAttributeReg.index; r.secondaryUVVarying = this._registerCache.getFreeVarying(); this._vertexCode += 'mov ' + r.secondaryUVVarying + ', ' + uvAttributeReg + '\n'; }; /** * Calculate the view direction. */ ShaderBase.prototype._compileViewDirCode = function () { var camPosReg = this._registerCache.getFreeVertexConstant(); var r = this._sharedRegisters; r.viewDirVarying = this._registerCache.getFreeVarying(); r.viewDirFragment = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(r.viewDirFragment, this.viewDirDependencies); this.cameraPositionIndex = camPosReg.index * 4; if (this.usesTangentSpace) { var temp = this._registerCache.getFreeVertexVectorTemp(); this._vertexCode += 'sub ' + temp + ', ' + camPosReg + ', ' + r.animatedPosition + '\n' + 'm33 ' + r.viewDirVarying + '.xyz, ' + temp + ', ' + r.animatedTangent + '\n' + 'mov ' + r.viewDirVarying + '.w, ' + r.animatedPosition + '.w\n'; } else { this._vertexCode += 'sub ' + r.viewDirVarying + ', ' + camPosReg + ', ' + r.globalPositionVertex + '\n'; this._registerCache.removeVertexTempUsage(this._sharedRegisters.globalPositionVertex); } //TODO is this required in all cases? (re: distancemappass) this._fragmentCode += 'nrm ' + r.viewDirFragment + '.xyz, ' + r.viewDirVarying + '\n' + 'mov ' + r.viewDirFragment + '.w, ' + r.viewDirVarying + '.w\n'; }; /** * Calculate the normal. */ ShaderBase.prototype._compileNormalCode = function () { var r = this._sharedRegisters; r.normalFragment = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(r.normalFragment, this.normalDependencies); //simple normal aquisition if no tangent space is being used if (this.outputsNormals && !this.outputsTangentNormals) { this._vertexCode += this._pass._getNormalVertexCode(this._registerCache, r); this._fragmentCode += this._pass._getNormalFragmentCode(this._registerCache, r); return; } var normalMatrix; if (!this.outputsNormals || !this.usesTangentSpace) { normalMatrix = new Array(3); normalMatrix[0] = this._registerCache.getFreeVertexConstant(); normalMatrix[1] = this._registerCache.getFreeVertexConstant(); normalMatrix[2] = this._registerCache.getFreeVertexConstant(); this._registerCache.getFreeVertexConstant(); this.sceneNormalMatrixIndex = normalMatrix[0].index * 4; r.normalVarying = this._registerCache.getFreeVarying(); } if (this.outputsNormals) { if (this.usesTangentSpace) { // normalize normal + tangent vector and generate (approximated) bitangent // used in m33 operation for view this._vertexCode += 'nrm ' + r.animatedNormal + '.xyz, ' + r.animatedNormal + '\n' + 'nrm ' + r.animatedTangent + '.xyz, ' + r.animatedTangent + '\n' + 'crs ' + r.bitangent + '.xyz, ' + r.animatedNormal + ', ' + r.animatedTangent + '\n'; this._fragmentCode += this._pass._getNormalFragmentCode(this._registerCache, r); } else { //Compiles the vertex shader code for tangent-space normal maps. r.tangentVarying = this._registerCache.getFreeVarying(); r.bitangentVarying = this._registerCache.getFreeVarying(); var temp = this._registerCache.getFreeVertexVectorTemp(); this._vertexCode += 'm33 ' + temp + '.xyz, ' + r.animatedNormal + ', ' + normalMatrix[0] + '\n' + 'nrm ' + r.animatedNormal + '.xyz, ' + temp + '\n' + 'm33 ' + temp + '.xyz, ' + r.animatedTangent + ', ' + normalMatrix[0] + '\n' + 'nrm ' + r.animatedTangent + '.xyz, ' + temp + '\n' + 'mov ' + r.tangentVarying + '.x, ' + r.animatedTangent + '.x \n' + 'mov ' + r.tangentVarying + '.z, ' + r.animatedNormal + '.x \n' + 'mov ' + r.tangentVarying + '.w, ' + r.normalInput + '.w \n' + 'mov ' + r.bitangentVarying + '.x, ' + r.animatedTangent + '.y \n' + 'mov ' + r.bitangentVarying + '.z, ' + r.animatedNormal + '.y \n' + 'mov ' + r.bitangentVarying + '.w, ' + r.normalInput + '.w \n' + 'mov ' + r.normalVarying + '.x, ' + r.animatedTangent + '.z \n' + 'mov ' + r.normalVarying + '.z, ' + r.animatedNormal + '.z \n' + 'mov ' + r.normalVarying + '.w, ' + r.normalInput + '.w \n' + 'crs ' + temp + '.xyz, ' + r.animatedNormal + ', ' + r.animatedTangent + '\n' + 'mov ' + r.tangentVarying + '.y, ' + temp + '.x \n' + 'mov ' + r.bitangentVarying + '.y, ' + temp + '.y \n' + 'mov ' + r.normalVarying + '.y, ' + temp + '.z \n'; this._registerCache.removeVertexTempUsage(r.animatedTangent); //Compiles the fragment shader code for tangent-space normal maps. var t = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(t, 1); var b = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(b, 1); var n = this._registerCache.getFreeFragmentVectorTemp(); this._registerCache.addFragmentTempUsages(n, 1); this._fragmentCode += 'nrm ' + t + '.xyz, ' + r.tangentVarying + '\n' + 'mov ' + t + '.w, ' + r.tangentVarying + '.w \n' + 'nrm ' + b + '.xyz, ' + r.bitangentVarying + '\n' + 'nrm ' + n + '.xyz, ' + r.normalVarying + '\n'; //compile custom fragment code for normal calcs this._fragmentCode += this._pass._getNormalFragmentCode(this._registerCache, r) + 'm33 ' + r.normalFragment + '.xyz, ' + r.normalFragment + ', ' + t + '\n' + 'mov ' + r.normalFragment + '.w, ' + r.normalVarying + '.w\n'; this._registerCache.removeFragmentTempUsage(b); this._registerCache.removeFragmentTempUsage(t); this._registerCache.removeFragmentTempUsage(n); } } else { // no output, world space is enough this._vertexCode += 'm33 ' + r.normalVarying + '.xyz, ' + r.animatedNormal + ', ' + normalMatrix[0] + '\n' + 'mov ' + r.normalVarying + '.w, ' + r.animatedNormal + '.w\n'; this._fragmentCode += 'nrm ' + r.normalFragment + '.xyz, ' + r.normalVarying + '\n' + 'mov ' + r.normalFragment + '.w, ' + r.normalVarying + '.w\n'; if (this.tangentDependencies > 0) { r.tangentVarying = this._registerCache.getFreeVarying(); this._vertexCode += 'm33 ' + r.tangentVarying + '.xyz, ' + r.animatedTangent + ', ' + normalMatrix[0] + '\n' + 'mov ' + r.tangentVarying + '.w, ' + r.animatedTangent + '.w\n'; } } if (!this.usesTangentSpace) this._registerCache.removeVertexTempUsage(r.animatedNormal); }; ShaderBase.prototype._compileAnimationCode = function () { //reset code this._animationVertexCode = ''; this._animationFragmentCode = ''; var r = this._sharedRegisters; //check to see if GPU animation is used if (this._usesAnimation) { var animationSet = this._renderMaterial.animationSet; this._animationVertexCode += animationSet.getAGALVertexCode(this, this._registerCache, r); if (this.uvDependencies > 0 && !this.usesUVTransform) this._animationVertexCode += animationSet.getAGALUVCode(this, this._registerCache, r); if (this.usesFragmentAnimation) this._animationFragmentCode += animationSet.getAGALFragmentCode(this, this._registerCache, r.shadedTarget); } else { // simply write attributes to targets, do not animate them // projection will pick up on targets[0] to do the projection var len = r.animatableAttributes.length; for (var i = 0; i < len; ++i) this._animationVertexCode += 'mov ' + r.animationTargetRegisters[i] + ', ' + r.animatableAttributes[i] + '\n'; if (this.uvDependencies > 0 && !this.usesUVTransform) this._animationVertexCode += 'mov ' + r.animatedUV + ',' + r.uvInput + '\n'; } }; ShaderBase.prototype.setVertexConst = function (index, x, y, z, w) { if (x === void 0) { x = 0; } if (y === void 0) { y = 0; } if (z === void 0) { z = 0; } if (w === void 0) { w = 0; } index *= 4; this.vertexConstantData[index++] = x; this.vertexConstantData[index++] = y; this.vertexConstantData[index++] = z; this.vertexConstantData[index] = w; }; ShaderBase.prototype.setVertexConstFromArray = function (index, data) { index *= 4; for (var i /*int*/ = 0; i < data.length; i++) this.vertexConstantData[index++] = data[i]; }; ShaderBase.prototype.setVertexConstFromMatrix = function (index, matrix) { index *= 4; var rawData = matrix._rawData; this.vertexConstantData[index++] = rawData[0]; this.vertexConstantData[index++] = rawData[4]; this.vertexConstantData[index++] = rawData[8]; this.vertexConstantData[index++] = rawData[12]; this.vertexConstantData[index++] = rawData[1]; this.vertexConstantData[index++] = rawData[5]; this.vertexConstantData[index++] = rawData[9]; this.vertexConstantData[index++] = rawData[13]; this.vertexConstantData[index++] = rawData[2]; this.vertexConstantData[index++] = rawData[6]; this.vertexConstantData[index++] = rawData[10]; this.vertexConstantData[index++] = rawData[14]; this.vertexConstantData[index++] = rawData[3]; this.vertexConstantData[index++] = rawData[7]; this.vertexConstantData[index++] = rawData[11]; this.vertexConstantData[index] = rawData[15]; }; ShaderBase.prototype.setFragmentConst = function (index, x, y, z, w) { if (x === void 0) { x = 0; } if (y === void 0) { y = 0; } if (z === void 0) { z = 0; } if (w === void 0) { w = 0; } index *= 4; this.fragmentConstantData[index++] = x; this.fragmentConstantData[index++] = y; this.fragmentConstantData[index++] = z; this.fragmentConstantData[index] = w; }; ShaderBase._store = {}; ShaderBase._abstractionClassPool = new Object(); return ShaderBase; }()); export { ShaderBase };