UNPKG

@awayjs/renderer

Version:
339 lines (338 loc) 13.1 kB
import { __extends } from "tslib"; import { AbstractionBase, WeakAssetSet } from '@awayjs/core'; import { ImageUtils, } from '@awayjs/stage'; import { PassEvent } from '../events/PassEvent'; import { MaterialEvent } from '../events/MaterialEvent'; /** * * @class away.pool.Passes */ var _Render_MaterialBase = /** @class */ (function (_super) { __extends(_Render_MaterialBase, _super); function _Render_MaterialBase() { var _this = _super.call(this) || this; /** * A list of material owners, renderables or custom Entities. */ _this._owners = new WeakAssetSet(); _this._passes = []; _this._invalidAnimation = true; _this._invalidRender = true; _this._invalidImages = true; _this._imageIndices = {}; _this._usesAnimation = false; _this.images = []; _this.samplers = []; /** * Indicates whether or not the renderable requires alpha blending during rendering. */ _this.requiresBlending = false; _this._onInvalidateTexturesDelegate = function (event) { return _this.onInvalidateTextures(event); }; _this._onInvalidatePassesDelegate = function (event) { return _this.onInvalidatePasses(event); }; _this._onPassInvalidateDelegate = function (event) { return _this.onPassInvalidate(event); }; return _this; } Object.defineProperty(_Render_MaterialBase.prototype, "animationSet", { get: function () { return this._animationSet; }, enumerable: false, configurable: true }); Object.defineProperty(_Render_MaterialBase.prototype, "material", { get: function () { return this._useWeak ? this._asset.deref() : this._asset; }, enumerable: false, configurable: true }); Object.defineProperty(_Render_MaterialBase.prototype, "renderElements", { get: function () { return this._pool; }, enumerable: false, configurable: true }); Object.defineProperty(_Render_MaterialBase.prototype, "numImages", { get: function () { if (this._invalidImages) this._updateImages(); return this._numImages; }, enumerable: false, configurable: true }); Object.defineProperty(_Render_MaterialBase.prototype, "renderOrderId", { get: function () { if (this._invalidRender) this._pUpdateRender(); if (this._invalidAnimation) this._updateAnimation(); return this._renderOrderId; }, enumerable: false, configurable: true }); Object.defineProperty(_Render_MaterialBase.prototype, "numPasses", { get: function () { if (this._invalidAnimation) this._updateAnimation(); return this._passes.length; }, enumerable: false, configurable: true }); _Render_MaterialBase.prototype.init = function (material, renderElements) { _super.prototype.init.call(this, material, renderElements, true); this.materialID = material.id; this._stage = renderElements.stage; material.addEventListener(MaterialEvent.INVALIDATE_TEXTURES, this._onInvalidateTexturesDelegate); material.addEventListener(MaterialEvent.INVALIDATE_PASSES, this._onInvalidatePassesDelegate); }; _Render_MaterialBase.prototype.activatePass = function (index) { this._activePass = this._passes[index]; //clear unused vertex streams var i; for (i = this._activePass.shader.numUsedStreams; i < this._stage.numUsedStreams; i++) this._stage.context.setVertexBufferAt(i, null); //clear unused texture streams for (i = this._activePass.shader.numUsedTextures; i < this._stage.numUsedTextures; i++) this._stage.context.setTextureAt(i, null); //activate shader object through pass this._activePass._activate(); }; _Render_MaterialBase.prototype.deactivatePass = function () { //deactivate shader object through pass this._activePass._deactivate(); this._stage.numUsedStreams = this._activePass.shader.numUsedStreams; this._stage.numUsedTextures = this._activePass.shader.numUsedTextures; }; // // MATERIAL MANAGEMENT // /** * Mark an IEntity as owner of this material. * Assures we're not using the same material across renderables with different animations, since the * Programs depend on animation. This method needs to be called when a material is assigned. * * @param owner The IEntity that had this material assigned * * @internal */ _Render_MaterialBase.prototype.addOwner = function (owner) { this._owners.add(owner); var animationSet; var animator = owner.entity.node.container.animator; if (animator) animationSet = animator.animationSet; if (owner.entity.node.container.animator) { if (this._animationSet && animationSet != this._animationSet) { throw new Error('A Material instance cannot be shared across ' + 'material owners with different animation sets'); } else { if (this._animationSet != animationSet) { this._animationSet = animationSet; this._invalidAnimation = true; } } } }; /** * Removes an IEntity as owner. * @param owner * * @internal */ _Render_MaterialBase.prototype.removeOwner = function (owner) { if (!this._owners.numAssets) //check if material is already disposed return; this._owners.remove(owner); if (!this._owners.numAssets) this.onClear(); }; _Render_MaterialBase.prototype.getImageIndex = function (texture, index) { if (index === void 0) { index = 0; } if (this._invalidImages) this._updateImages(); return this._imageIndices[texture.id][index]; }; /** * */ _Render_MaterialBase.prototype.onClear = function () { var len = this._passes.length; for (var i = 0; i < len; i++) { this._passes[i].removeEventListener(PassEvent.INVALIDATE, this._onPassInvalidateDelegate); this._passes[i].dispose(); } this._passes.length = 0; this._owners.clear(); var material = this.material; if (material) { material.removeEventListener(MaterialEvent.INVALIDATE_TEXTURES, this._onInvalidateTexturesDelegate); material.removeEventListener(MaterialEvent.INVALIDATE_PASSES, this._onInvalidatePassesDelegate); } this._animationSet = null; this._stage = null; this._invalidAnimation = true; this._invalidRender = true; this._invalidImages = true; this._imageIndices = {}; this._usesAnimation = false; this._activePass = null; this.images.length = 0; this.samplers.length = 0; _super.prototype.onClear.call(this); }; /** * */ _Render_MaterialBase.prototype.onInvalidatePasses = function (event) { var len = this._passes.length; for (var i = 0; i < len; i++) this._passes[i].invalidate(); this._invalidAnimation = true; this._invalidImages = true; }; /** * Listener for when a pass's shader code changes. It recalculates the render order id. */ _Render_MaterialBase.prototype.onPassInvalidate = function (event) { this._invalidAnimation = true; }; /** * */ _Render_MaterialBase.prototype.onInvalidateTextures = function (event) { this._owners.forEach(function (asset) { return asset._onInvalidateStyle(); }); }; /** * */ _Render_MaterialBase.prototype.onInvalidate = function () { _super.prototype.onInvalidate.call(this); this._invalidRender = true; this._invalidAnimation = true; //prevent infinite loop with cacheRenderer invalidation if (this.renderElements.renderer != this.material) this.renderElements.renderer.invalidate(); }; /** * Removes all passes from the surface */ _Render_MaterialBase.prototype._pClearPasses = function () { var len = this._passes.length; for (var i = 0; i < len; ++i) this._passes[i].removeEventListener(PassEvent.INVALIDATE, this._onPassInvalidateDelegate); this._passes.length = 0; }; /** * Adds a pass to the surface * @param pass */ _Render_MaterialBase.prototype._pAddPass = function (pass) { this._passes.push(pass); pass.addEventListener(PassEvent.INVALIDATE, this._onPassInvalidateDelegate); }; /** * Removes a pass from the surface. * @param pass The pass to be removed. */ _Render_MaterialBase.prototype._pRemovePass = function (pass) { pass.removeEventListener(PassEvent.INVALIDATE, this._onPassInvalidateDelegate); this._passes.splice(this._passes.indexOf(pass), 1); }; /** * Performs any processing that needs to occur before any of its passes are used. * * @private */ _Render_MaterialBase.prototype._pUpdateRender = function () { if (this._invalidImages) this._updateImages(); this._invalidRender = false; }; /** * * @param surface */ _Render_MaterialBase.prototype._updateAnimation = function () { // if (this._invalidRender) // this._pUpdateRender(); this._invalidAnimation = false; var usesAnimation = this._getEnabledGPUAnimation(); var renderOrderId = 0; var mult = 1; var shader; var len = this._passes.length; for (var i = 0; i < len; i++) { shader = this._passes[i].shader; shader.usesAnimation = usesAnimation; // this is getter, this enforce update programData // renderOrderId += shader.programData.id * mult; if (shader._programData) { renderOrderId += shader._programData.id * mult; } else { renderOrderId += shader.programData.id * mult; } mult *= 1000; } if (this._usesAnimation != usesAnimation) { this._usesAnimation = usesAnimation; this._owners.forEach(function (asset) { return asset._onInvalidateElements(); }); } this._renderOrderId = renderOrderId; }; _Render_MaterialBase.prototype._updateImages = function () { var material = this.material; this._invalidImages = false; var style = material.style; var numTextures = material.getNumTextures(); var texture; var numImages; var images; var index = 0; for (var i = 0; i < numTextures; i++) { texture = material.getTextureAt(i); numImages = texture.getNumImages(); images = this._imageIndices[texture.id] = []; for (var j = 0; j < numImages; j++) { this.images[index] = (style === null || style === void 0 ? void 0 : style.getImageAt(texture, j)) || texture.getImageAt(j) || ImageUtils.getDefaultImage2D(); this.samplers[index] = (style === null || style === void 0 ? void 0 : style.getSamplerAt(texture, j)) || texture.getSamplerAt(j) || ImageUtils.getDefaultImageSampler(); images[j] = index++; } } this._numImages = index; }; /** * test if animation will be able to run on gpu BEFORE compiling materials * test if the shader objects supports animating the animation set in the vertex shader * if any object using this material fails to support accelerated animations for any of the shader objects, * we should do everything on cpu (otherwise we have the cost of both gpu + cpu animations) */ _Render_MaterialBase.prototype._getEnabledGPUAnimation = function () { if (this._animationSet) { this._animationSet.resetGPUCompatibility(); var len = this._passes.length; var shader_1; for (var i = 0; i < len; i++) { shader_1 = this._passes[i].shader; shader_1.usesAnimation = false; this._owners.forEach(function (asset) { if (asset.entity.node.container.animator) asset.entity.node.container.animator.testGPUCompatibility(shader_1); }); } return !this._animationSet.usesCPU; } return false; }; return _Render_MaterialBase; }(AbstractionBase)); export { _Render_MaterialBase };