@awayjs/renderer
Version:
Renderer for AwayJS
764 lines (758 loc) • 32.8 kB
JavaScript
import { __extends } from "tslib";
import { Matrix3D, Vector3D, AbstractionBase, Box, Rectangle, } from '@awayjs/core';
import { ContextGLBlendFactor, ContextGLCompareMode, ContextGLStencilAction, ContextGLTriangleFace, StageEvent, ContextGLClearMask, ImageSampler, BlendMode, isNativeBlend, Settings as StageSettings } from '@awayjs/stage';
import { ViewEvent, ContainerNode, PickGroup, } from '@awayjs/view';
import { RenderEntity } from './base/RenderEntity';
import { RenderGroup } from './RenderGroup';
import { RenderableMergeSort } from './sort/RenderableMergeSort';
import { Style } from './base/Style';
import { StyleEvent } from './events/StyleEvent';
import { AbstractionSet } from '@awayjs/core/dist/lib/base/AbstractionSet';
/**
* RendererBase forms an abstract base class for classes that are used in the rendering pipeline to render the
* contents of a partition
*
* @class away.render.RendererBase
*/
var RendererBase = /** @class */ (function (_super) {
__extends(RendererBase, _super);
function RendererBase() {
var _this = _super.call(this) || this;
_this._renderObjects = {};
_this._renderMatrix = new Matrix3D();
_this._boundsScale = 1;
_this._paddedBounds = new Rectangle();
_this._bounds = new Box();
_this._boundsDirty = true;
_this._mappers = new Array();
_this._elementsPools = {};
_this._cameraForward = new Vector3D();
_this._depthTextureDirty = true;
_this._depthPrepass = false;
_this._pNumElements = 0;
_this._opaqueRenderables = [];
_this._blendedRenderables = [];
_this._disableColor = false;
_this._disableClear = false;
_this._renderBlended = true;
_this._numCullPlanes = 0;
/**
*
*/
_this.renderableSorter = new RenderableMergeSort();
_this.abstractions = new AbstractionSet(_this);
_this._onInvalidateProperties = function (_event) { return _this._onInvalidateStyle(); };
_this._onSizeInvalidateDelegate = function (event) { return _this.onSizeInvalidate(event); };
_this._onContextUpdateDelegate = function (event) { return _this.onContextUpdate(event); };
return _this;
}
Object.defineProperty(RendererBase.prototype, "cullPlanes", {
/**
*
*/
get: function () {
return this._customCullPlanes;
},
set: function (value) {
this._customCullPlanes = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "renderBlended", {
get: function () {
return this._renderBlended;
},
set: function (value) {
this._renderBlended = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "disableColor", {
get: function () {
return this._disableColor;
},
set: function (value) {
if (this._disableColor == value)
return;
this._disableColor = value;
this._invalid = true;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "disableClear", {
get: function () {
return this._disableClear;
},
set: function (value) {
if (this._disableClear == value)
return;
this._disableClear = value;
this._invalid = true;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "numElements", {
/**
*
*/
get: function () {
return this._pNumElements;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "context", {
get: function () {
return this._context;
},
enumerable: false,
configurable: true
});
RendererBase.prototype.getPaddedBounds = function () {
if (this._boundsDirty)
this._updateBounds();
return this._paddedBounds;
};
RendererBase.prototype.getBounds = function () {
if (this._boundsDirty)
this._updateBounds();
return this._bounds;
};
RendererBase.prototype.getBoundsScale = function () {
if (this._boundsDirty)
this._updateBounds();
return this._boundsScale;
};
RendererBase.prototype.getParentPosition = function () {
if (this._boundsDirty)
this._updateBounds();
return this._parentPosition;
};
Object.defineProperty(RendererBase.prototype, "style", {
/**
*
*/
get: function () {
if (this._boundsDirty)
this._updateBounds();
return this._style;
},
set: function (value) {
if (this._style == value)
return;
if (this._style)
this._style.removeEventListener(StyleEvent.INVALIDATE_PROPERTIES, this._onInvalidateProperties);
this._style = value;
if (this._style)
this._style.addEventListener(StyleEvent.INVALIDATE_PROPERTIES, this._onInvalidateProperties);
this._onInvalidateStyle();
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "node", {
get: function () {
return this._asset;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "group", {
get: function () {
return this._pool;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "blendMode", {
get: function () {
var containerBlend = this.node.container.blendMode;
// native blends
if (isNativeBlend(containerBlend))
return containerBlend;
return BlendMode.LAYER;
},
enumerable: false,
configurable: true
});
Object.defineProperty(RendererBase.prototype, "useNonNativeBlend", {
get: function () {
return StageSettings.USE_NON_NATIVE_BLEND
&& this._asset.container.blendMode
&& this._asset.container.blendMode !== BlendMode.NORMAL
&& this.blendMode == BlendMode.LAYER;
},
enumerable: false,
configurable: true
});
/**
* Creates a new RendererBase object.
*/
RendererBase.prototype.init = function (node, group) {
_super.prototype.init.call(this, node, group);
this._parentNode = node.parent;
this.style = new Style();
this.view = node.view;
this.stage = this.view.stage;
this.stage.addEventListener(StageEvent.CONTEXT_CREATED, this._onContextUpdateDelegate);
this.stage.addEventListener(StageEvent.CONTEXT_RECREATED, this._onContextUpdateDelegate);
this.view.addEventListener(ViewEvent.INVALIDATE_SIZE, this._onSizeInvalidateDelegate);
this._boundsPicker = PickGroup.getInstance().getBoundsPicker(this.node);
if (this.stage.context)
this._context = this.stage.context;
};
RendererBase.prototype.onClear = function () {
this.clear();
_super.prototype.onClear.call(this);
this.stage.removeEventListener(StageEvent.CONTEXT_CREATED, this._onContextUpdateDelegate);
this.stage.removeEventListener(StageEvent.CONTEXT_RECREATED, this._onContextUpdateDelegate);
this.view.removeEventListener(ViewEvent.INVALIDATE_SIZE, this._onSizeInvalidateDelegate);
this.parentRenderer = null;
this._parentNode = null;
this.view = null;
this.stage = null;
this.style = null;
this._boundsPicker = null;
this._activeMasksDirty = false;
this._activeMaskOwners = null;
this._renderEntity = null;
this.abstractions.forEach(function (entity) { return entity.onClear(); });
this.resetHead();
for (var key in this._elementsPools) {
this._elementsPools[key].clear();
delete this._elementsPools[key];
}
this._boundsDirty = true;
this._disableColor = false;
this._disableClear = false;
this._renderBlended = true;
};
RendererBase.prototype.onInvalidate = function () {
_super.prototype.onInvalidate.call(this);
this._boundsDirty = true;
};
RendererBase.prototype.update = function (node) {
//update mappers
var len = this._mappers.length;
for (var i = 0; i < len; i++)
this._mappers[i].update(node);
};
RendererBase.prototype._addMapper = function (mapper) {
if (this._mappers.indexOf(mapper) != -1)
return;
this._mappers.push(mapper);
};
RendererBase.prototype._removeMapper = function (mapper) {
var index = this._mappers.indexOf(mapper);
if (index != -1)
this._mappers.splice(index, 1);
};
RendererBase.prototype.getRenderElements = function (elements) {
return this._elementsPools[elements.assetType]
|| (this._elementsPools[elements.assetType] = new (RenderGroup.getRenderElementsClass(elements))(this));
};
RendererBase.prototype.requestAbstraction = function (asset) {
return RendererBase._store.length ? RendererBase._store.pop() : new RenderEntity();
};
RendererBase.prototype.storeAbstraction = function (abstraction) {
RendererBase._store.push(abstraction);
};
/**
* Renders the potentially visible geometry to the back buffer or texture.
* @param target An option target texture to render to.
* @param surfaceSelector The index of a CubeTexture's face to render to.
* @param additionalClearMask Additional clear mask information, in case extra clear channels are to be omitted.
*/
RendererBase.prototype.render = function (enableDepthAndStencil, surfaceSelector, mipmapSelector, maskConfig) {
if (enableDepthAndStencil === void 0) { enableDepthAndStencil = true; }
if (surfaceSelector === void 0) { surfaceSelector = 0; }
if (mipmapSelector === void 0) { mipmapSelector = 0; }
if (maskConfig === void 0) { maskConfig = 0; }
//TODO refactor setTarget so that rendertextures are created before this check
// if (!this._stage || !this._context)
// return;
this._maskConfig = maskConfig;
//check for mask rendering
if (this._maskConfig) {
this._disableClear = true;
this._disableColor = true;
}
this.update(this._asset);
// invalidate mipmaps (if target exists) to regenerate if required
if (this.view.target)
this.view.target.invalidateMipmaps();
// this._pRttViewProjectionMatrix.copyFrom(projection.viewMatrix3D);
// this._pRttViewProjectionMatrix.appendScale(this.textureRatioX, this.textureRatioY, 1);
/*
if (_backgroundImageRenderer)
_backgroundImageRenderer.render();
*/
if (!StageSettings.USE_NON_NATIVE_BLEND || this._invalid)
this.traverse();
this.executeRender(enableDepthAndStencil, surfaceSelector, mipmapSelector);
//line required for correct rendering when using away3d with starling.
//DO NOT REMOVE UNLESS STARLING INTEGRATION IS RETESTED!
//this._context.setDepthTest(false, ContextGLCompareMode.LESS_EQUAL); //oopsie
if (!this.view.shareContext || this.view.target) {
if (this._snapshotRequired && this._snapshotBitmapImage2D) {
this._context.drawToBitmapImage2D(this._snapshotBitmapImage2D);
this._snapshotRequired = false;
}
}
};
RendererBase.prototype.resetHead = function () {
//reset head values
this._blendedRenderables = [];
this._opaqueRenderables = [];
};
RendererBase.prototype.traverse = function () {
this.resetHead();
this._invalid = false;
this._pNumElements = 0;
this._activeMaskOwners = null;
this._cameraTransform = this.view.projection.transform.matrix3D;
this._cameraForward = this.view.projection.transform.forwardVector;
this._cullPlanes = this._customCullPlanes ? this._customCullPlanes : this.node.getRoot(true).view.projection.viewFrustumPlanes;
this._numCullPlanes = this._cullPlanes ? this._cullPlanes.length : 0;
this._maskId = this._asset.getMaskId();
RendererBase._collectionMark++;
this._asset.acceptTraverser(this);
//sort the resulting renderables
if (this.renderableSorter) {
// this._pOpaqueRenderableHead = this.renderableSorter.sortOpaqueRenderables(this._pOpaqueRenderableHead);
// this._pBlendedRenderableHead = this.renderableSorter.sortBlendedRenderables(this._pBlendedRenderableHead);
}
};
RendererBase.prototype._iRenderCascades = function (enableDepthAndStencil, surfaceSelector) {
// this._stage.setRenderTarget(target, true, 0);
// this._context.clear(1, 1, 1, 1, 1, 0);
if (enableDepthAndStencil === void 0) { enableDepthAndStencil = true; }
if (surfaceSelector === void 0) { surfaceSelector = 0; }
// this._context.setBlendFactors(ContextGLBlendFactor.ONE, ContextGLBlendFactor.ZERO);
// this._context.setDepthTest(true, ContextGLCompareMode.LESS);
// var head:_Render_RenderableBase = this._pOpaqueRenderableHead;
// var first:boolean = true;
// //TODO cascades must have separate collectors, rather than separate draw commands
// for (var i:number = numCascades - 1; i >= 0; --i) {
// //this._stage.scissorRect = scissorRects[i];
// //this.drawCascadeRenderables(head, cameras[i], first? null : cameras[i].frustumPlanes);
// first = false;
// }
// line required for correct rendering when using away3d with starling.
// DO NOT REMOVE UNLESS STARLING INTEGRATION IS RETESTED!
// this._context.setDepthTest(false, ContextGLCompareMode.LESS_EQUAL);
};
/**
* Renders the potentially visible geometry to the back buffer or texture. Only executed if everything is set up.
*
* @param target An option target texture to render to.
* @param surfaceSelector The index of a CubeTexture's face to render to.
* @param additionalClearMask Additional clear mask information, in case extra clear channels are to be omitted.
*/
RendererBase.prototype.executeRender = function (enableDepthAndStencil, surfaceSelector, mipmapSelector) {
if (enableDepthAndStencil === void 0) { enableDepthAndStencil = true; }
if (surfaceSelector === void 0) { surfaceSelector = 0; }
if (mipmapSelector === void 0) { mipmapSelector = 0; }
//initialise blend mode
this._context.setBlendFactors(ContextGLBlendFactor.ONE, ContextGLBlendFactor.ZERO);
//initialise depth test
this._context.setDepthTest(true, ContextGLCompareMode.LESS_EQUAL);
//initialise color mask
if (this._disableColor)
this._context.setColorMask(false, false, false, false);
else
this._context.setColorMask(true, true, true, true);
//TODO: allow sharedContexts for image targets
this.view.clear(!this._depthPrepass && !this._disableClear, enableDepthAndStencil, surfaceSelector, mipmapSelector, (!this.view.shareContext || this.view.target)
? ContextGLClearMask.ALL
: ContextGLClearMask.DEPTH);
//initialise stencil
if (this._maskConfig)
this._context.enableStencil();
else
this._context.disableStencil();
this.drawRenderables(this._opaqueRenderables);
if (this._renderBlended)
this.drawRenderables(this._blendedRenderables);
};
/*
* Will draw the renderer's output on next render to the provided bitmap data.
* */
RendererBase.prototype.queueSnapshot = function (bmd) {
this._snapshotRequired = true;
this._snapshotBitmapImage2D = bmd;
};
//private drawCascadeRenderables(renderRenderable:_Render_RenderableBase, camera:Camera, cullPlanes:Array<Plane3D>)
//{
// var renderRenderable2:_Render_RenderableBase;
// var render:_Render_MaterialBase;
// var pass:IPass;
//
// while (renderRenderable) {
// renderRenderable2 = renderRenderable;
// render = renderRenderable.render;
// pass = render.passes[0] //assuming only one pass per material
//
// this.activatePass(renderRenderable, pass, camera);
//
// do {
// // if completely in front, it will fall in a different cascade
// // do not use near and far planes
// if (!cullPlanes || renderRenderable2.node.worldBounds.isInFrustum(cullPlanes, 4)) {
// renderRenderable2._iRender(pass, camera, this._pRttViewProjectionMatrix);
// } else {
// renderRenderable2.cascaded = true;
// }
//
// renderRenderable2 = renderRenderable2.next;
//
// } while (renderRenderable2 && renderRenderable2.render == render && !renderRenderable2.cascaded);
//
// this.deactivatePass(renderRenderable, pass);
//
// renderRenderable = renderRenderable2;
// }
//}
/**
* Draw a list of renderables.
*
* @param renderables The renderables to draw.
*/
RendererBase.prototype.drawRenderables = function (renderRenderables) {
var index = 0;
var len = renderRenderables.length;
var renderRenderable = renderRenderables[index];
var renderMaterial;
var numPasses;
var i;
var r;
while (index < len) {
renderMaterial = renderRenderable.renderMaterial;
numPasses = renderMaterial ? renderMaterial.numPasses : 1;
if (this._activeMasksDirty || this._checkMaskOwners(renderRenderable.entity.maskOwners)) {
if (!(this._activeMaskOwners = renderRenderable.entity.maskOwners)) {
//re-establish stencil settings (if not inside another mask)
if (!this._maskConfig)
this._context.disableStencil();
}
else {
this._renderMasks(this._activeMaskOwners);
}
this._activeMasksDirty = false;
}
//iterate through each shader object
for (var p = 0; p < numPasses; p++) {
renderMaterial && renderMaterial.activatePass(p);
i = index;
r = renderRenderable;
do {
///console.log("maskOwners", renderRenderable2.maskOwners);
r.draw();
if (++i == len)
break;
r = renderRenderables[i];
} while (r.renderMaterial == renderMaterial
&& !(this._activeMasksDirty = this._checkMaskOwners(r.entity.node.getMaskOwners())));
renderMaterial && renderMaterial.deactivatePass();
}
index = i;
renderRenderable = r;
}
};
/**
* Assign the context once retrieved
*/
RendererBase.prototype.onContextUpdate = function (event) {
this._context = this.stage.context;
};
/*
public get iBackground():Texture2DBase
{
return this._background;
}
*/
/*
public set iBackground(value:Texture2DBase)
{
if (this._backgroundImageRenderer && !value) {
this._backgroundImageRenderer.dispose();
this._backgroundImageRenderer = null;
}
if (!this._backgroundImageRenderer && value)
{
this._backgroundImageRenderer = new BackgroundImageRenderer(this._stage);
}
this._background = value;
if (this._backgroundImageRenderer)
this._backgroundImageRenderer.texture = value;
}
*/
/*
public get backgroundImageRenderer():BackgroundImageRenderer
{
return _backgroundImageRenderer;
}
*/
/**
*
*/
RendererBase.prototype.onSizeInvalidate = function (event) {
if (this._pRttBufferManager) {
this._pRttBufferManager.viewWidth = this.view.width;
this._pRttBufferManager.viewHeight = this.view.height;
}
this._depthTextureDirty = true;
this.onInvalidate();
};
/**
*
* @param node
* @returns {boolean}
*/
RendererBase.prototype.enterNode = function (node) {
var maskOrFrustrum = (this._maskConfig
|| node.isInFrustum(this._asset, this._cullPlanes, this._numCullPlanes, PickGroup.getInstance()));
var enter = node._collectionMark != RendererBase._collectionMark
&& node.isRenderable()
&& maskOrFrustrum
&& node.getMaskId() == this._maskId;
node._collectionMark = RendererBase._collectionMark;
return enter;
};
RendererBase.prototype.getTraverser = function (rootNode) {
if (rootNode.renderToImage) {
//new node for the container
var node = rootNode.getLocalNode();
var boundsPicker = PickGroup.getInstance().getBoundsPicker(rootNode);
if (!boundsPicker._isInFrustumInternal(this._asset.getRoot(true), this._cullPlanes, this._numCullPlanes))
return;
var traverser = this._traverserGroup.getRenderer(node);
traverser.renderableSorter = null;
traverser.parentRenderer = this;
//if (this._invalid) {
this._renderEntity = this.abstractions.getAbstraction(node);
// project onto camera's z-axis
this._renderEntity.zIndex = this._cameraTransform.position
.subtract(rootNode.getPosition())
.dotProduct(this._cameraForward) + rootNode.container.zOffset;
//save sceneTransform
this._renderEntity.renderSceneTransform = rootNode.getRenderMatrix3D(this._cameraTransform);
//save colorTransform (null for CacheRenderer)
this._renderEntity.colorTransform = ContainerNode.nullColorTransform;
//save mask owners
this._renderEntity.maskOwners = rootNode.getMaskOwners();
//apply CacheRenderer as renderable
this.applyTraversable(traverser);
return traverser;
}
return this;
};
RendererBase.prototype.applyEntity = function (node) {
var _a, _b;
var entity = node.container.getEntity();
if (entity) {
this._pickEntity = PickGroup.getInstance().abstractions.getAbstraction(node);
if (!this._pickEntity._isInFrustumInternal(this._asset.getRoot(true), this._cullPlanes, this._numCullPlanes))
return;
this._renderEntity = this.abstractions.getAbstraction(node);
// project onto camera's z-axis
this._renderEntity.zIndex = this._cameraTransform.position
.subtract(node.getPosition())
.dotProduct(this._cameraForward) + node.container.zOffset;
//save sceneTransform
this._renderEntity.renderSceneTransform = node.getRenderMatrix3D(this._cameraTransform);
//save colorTransform
this._renderEntity.colorTransform = node.getColorTransform();
//save mask owners
this._renderEntity.maskOwners = node.getMaskOwners();
//collect renderables
entity._acceptTraverser(this);
}
else {
//check if we have a RenderEntity abstraction and if so, clear it!
(_a = this.abstractions.checkAbstraction(node)) === null || _a === void 0 ? void 0 : _a.onClear();
(_b = PickGroup.getInstance().abstractions.checkAbstraction(node)) === null || _b === void 0 ? void 0 : _b.onClear();
}
};
RendererBase.prototype.applyTraversable = function (renderable) {
var renderRenderable = this._renderEntity.abstractions.getAbstraction(renderable);
//store renderable properties
renderRenderable.cascaded = false;
var renderMaterial = renderRenderable.renderMaterial;
renderRenderable.materialID = renderMaterial.materialID;
renderRenderable.renderOrderId = renderMaterial.renderOrderId;
if (renderMaterial.requiresBlending) {
this._blendedRenderables.push(renderRenderable);
}
else {
this._opaqueRenderables.push(renderRenderable);
}
//need to re-trigger stageElements getter in case animator has changed
this._pNumElements += renderRenderable.stageElements.elements.numElements;
};
RendererBase.prototype._renderMasks = function (maskOwners) {
//calculate the bit index of maskConfig devided by two
var halfBitIndex = Math.log2(this._maskConfig) >> 1;
//create a new base and config value for the mask to be rendered
//maskBase set to next odd significant bit
var newMaskBase = this._maskConfig ? Math.pow(2, (halfBitIndex + 1) << 1) : 1;
var newMaskConfig = newMaskBase;
if (newMaskConfig > 0xff) {
console.warn('[RenderBase] Mask bit overflow, maskConfig %d', newMaskConfig);
return;
}
this._context.enableStencil();
var numLayers = maskOwners.length;
var children;
var numChildren;
var first = true;
for (var i = 0; i < numLayers; ++i) {
children = maskOwners[i].getMasks();
numChildren = children.length;
if (numChildren) {
this._context.setStencilActions(ContextGLTriangleFace.FRONT_AND_BACK, (first) ? ContextGLCompareMode.ALWAYS
: ContextGLCompareMode.EQUAL, ContextGLStencilAction.SET, ContextGLStencilAction.SET, ContextGLStencilAction.KEEP);
first = false;
//flips between read odd write even to read even write odd
this._context.setStencilReferenceValue(0xFF, newMaskConfig, newMaskConfig = (newMaskConfig & newMaskBase) + newMaskBase);
//clears write mask to zero
this._context.clear(0, 0, 0, 0, 0, 0, ContextGLClearMask.STENCIL);
for (var j = 0; j < numChildren; ++j)
this._maskGroup.getRenderer(children[j]).render(true, 0, 0, newMaskConfig);
}
}
if (!first) {
this._context.setStencilActions(ContextGLTriangleFace.FRONT_AND_BACK, ContextGLCompareMode.EQUAL, ContextGLStencilAction.SET, ContextGLStencilAction.SET, ContextGLStencilAction.KEEP);
}
//reads from mask output, writes to previous mask state
this._context.setStencilReferenceValue(0xFF, newMaskConfig, this._maskConfig);
//re-establish color mask settings (if not inside another mask)
if (!this._disableColor) {
this._context.setColorMask(true, true, true, true);
}
};
RendererBase.prototype._checkMaskOwners = function (maskOwners) {
if (this._activeMaskOwners == null || maskOwners == null)
return Boolean(this._activeMaskOwners != maskOwners);
if (this._activeMaskOwners.length != maskOwners.length)
return true;
var numLayers = maskOwners.length;
var numMasks;
var masks;
var activeNumMasks;
var activeMasks;
for (var i = 0; i < numLayers; i++) {
masks = maskOwners[i].getMasks();
numMasks = masks.length;
activeMasks = this._activeMaskOwners[i].getMasks();
activeNumMasks = activeMasks.length;
if (activeNumMasks != numMasks)
return true;
for (var j = 0; j < numMasks; j++) {
if (activeMasks[j] != masks[j])
return true;
}
}
return false;
};
RendererBase.prototype._onInvalidateStyle = function () {
for (var key in this._renderObjects)
this._renderObjects[key]._onInvalidateStyle();
};
RendererBase.prototype._updateBounds = function () {
this._boundsDirty = false;
var node = this._asset;
var matrix3D = this._renderMatrix;
var container = node.container;
var rootView = node.getRoot().view;
var pad = this._paddedBounds;
var scale = this._boundsScale = Math.min(3, rootView.height * this.stage.pixelRatio * rootView.projection.scale / 1000);
if (this._parentNode) {
matrix3D.copyFrom(this._parentNode.getMatrix3D());
}
else {
matrix3D.identity();
}
if (scale !== 1)
matrix3D.appendScale(scale, scale, scale);
var bounds = this._boundsPicker.getBoxBounds(node, true, true);
if (!bounds) {
console.error('[CachedRenderer] Bounds invalid, supress calculation', node);
return;
}
if (isNaN(bounds.width) || isNaN(bounds.height)) {
console.error('[CachedRenderer] Bounds invalid (NaN), supress calculation', node);
return;
}
this._bounds.copyFrom(bounds);
matrix3D.transformBox(this._bounds, this._bounds);
matrix3D.invert();
if (this.useNonNativeBlend) {
//set to bounds of parent
var parentBounds = this.parentRenderer.getPaddedBounds();
pad.setTo(parentBounds.x, parentBounds.y, parentBounds.width, parentBounds.height);
this._style.image = this.parentRenderer.style.image;
this._style.sampler = new ImageSampler(false, false, false);
}
else {
pad.setTo(this._bounds.x, this._bounds.y, this._bounds.width, this._bounds.height);
if (container.filters && container.filters.length > 0) {
container.filters.forEach(function (e) { return e && (e.imageScale = scale); });
this.stage.filterManager.computeFiltersPadding(pad, container.filters, pad);
}
pad.x = (pad.x - 2) | 0;
pad.y = (pad.y - 2) | 0;
pad.width = (pad.width + 4) | 0;
pad.height = (pad.height + 4) | 0;
var parentBounds = void 0;
var parentPosition = void 0;
if (this._parentNode) {
parentBounds = this.parentRenderer.getPaddedBounds();
parentPosition = this.parentRenderer.getParentPosition();
this._parentPosition = this._parentNode.getMatrix3D().position.clone();
this._parentPosition.scaleBy(scale);
}
else {
parentBounds = new Rectangle(0, 0, this.view.width * this.stage.pixelRatio, this.view.height * this.stage.pixelRatio);
parentPosition = new Vector3D();
this._parentPosition = new Vector3D();
}
if (pad.left < -parentPosition.x)
pad.left = -parentPosition.x;
if (pad.top < -parentPosition.y)
pad.top = -parentPosition.y;
if (pad.right > parentBounds.right - parentPosition.x)
pad.right = parentBounds.right - parentPosition.x;
if (pad.bottom > parentBounds.bottom - parentPosition.y)
pad.bottom = parentBounds.bottom - parentPosition.y;
if (pad.width * pad.height == 0) {
throw new Error('Cannot have image with size 0 * 0');
}
}
};
RendererBase.prototype._initRender = function (target) {
var pad = this._paddedBounds;
var scale = this._boundsScale;
var matrix3D = this._renderMatrix;
var view = this.view;
var proj = view.projection;
matrix3D._rawData[14] = -1000;
// without this we will handle empty image when target is big (scale > +3)
proj.far = 4000;
proj.near = 1;
proj.transform.matrix3D = matrix3D;
proj.ratio = (target.width / target.height);
proj.originX = -1 - 2 * pad.x / target.width;
proj.originY = -1 - 2 * pad.y / target.height;
proj.scale = scale * 1000 / target.height;
view.target = target;
};
RendererBase._store = [];
RendererBase._collectionMark = 0;
return RendererBase;
}(AbstractionBase));
export { RendererBase };