@awayjs/renderer
Version:
Renderer for AwayJS
290 lines (223 loc) • 6.19 kB
text/typescript
import {
AbstractMethodError,
Matrix,
AbstractionBase,
} from '@awayjs/core';
import {
Stage,
_Stage_ImageBase,
ImageSampler,
} from '@awayjs/stage';
import { MaterialUtils } from '../utils/MaterialUtils';
import { _Render_MaterialBase } from './_Render_MaterialBase';
import { _Stage_ElementsBase } from './_Stage_ElementsBase';
import { IPass } from './IPass';
import { IMaterial } from './IMaterial';
import { RenderEntity } from './RenderEntity';
import { ITexture } from './ITexture';
import { Style } from './Style';
import { IShaderBase } from './IShaderBase';
import { IRenderable } from './IRenderable';
/**
* @class RenderableListItem
*/
export class _Render_RenderableBase extends AbstractionBase {
private _renderMaterial: _Render_MaterialBase;
private _materialDirty: boolean = true;
private _stageElements: _Stage_ElementsBase;
private _elementsDirty: boolean = true;
private _styleDirty: boolean = true;
private _images: _Stage_ImageBase[] = [];
private _samplers: ImageSampler[] = [];
private _uvMatrix: Matrix;
public JOINT_INDEX_FORMAT: string;
public JOINT_WEIGHT_FORMAT: string;
public _count: number = 0;
public _offset: number = 0;
protected _stage: Stage;
/**
*
*/
public get images(): Array<_Stage_ImageBase> {
if (this._styleDirty)
this._updateStyle();
return this._images;
}
/**
*
*/
public get samplers(): Array<ImageSampler> {
if (this._styleDirty)
this._updateStyle();
return this._samplers;
}
/**
*
*/
public get uvMatrix(): Matrix {
if (this._styleDirty)
this._updateStyle();
return this._uvMatrix;
}
/**
*
*/
public next: _Render_RenderableBase;
/**
*
*/
public materialID: number;
/**
*
*/
public renderOrderId: number;
/**
*
*/
public cascaded: boolean;
/**
*
* @returns {_Stage_ElementsBase}
*/
public get stageElements(): _Stage_ElementsBase {
if (this._elementsDirty)
this._updateElements();
return this._stageElements;
}
/**
*
* @returns {_Render_MaterialBase}
*/
public get renderMaterial(): _Render_MaterialBase {
if (this._materialDirty)
this._updateMaterial();
return this._renderMaterial;
}
public get entity(): RenderEntity {
return <RenderEntity> this._pool;
}
public get renderable(): IRenderable {
return this._useWeak ? (<WeakRef<IRenderable>> this._asset).deref() : <IRenderable> this._asset;
}
constructor() {
super();
}
/**
*
* @param renderable
* @param sourceEntity
* @param surface
* @param renderer
*/
public init(renderable: IRenderable, entity: RenderEntity): void {
super.init(renderable, entity, true);
//store references
this._stage = entity.renderer.stage;
renderable._renderObjects[entity.id] = this;
}
/**
* Renders an object to the current render target.
*
* @private
*/
public draw(): void {
const pass: IPass = this._renderMaterial._activePass;
pass._setRenderState(this);
const shader: IShaderBase = pass.shader;
const elements: _Stage_ElementsBase = this.stageElements;
if (shader.activeElements != elements) {
shader.activeElements = elements;
elements._setRenderState(this, shader);
}
elements.draw(this, shader, this._count, this._offset);
}
public onClear(): void {
const renderable: IRenderable = this.renderable;
if (renderable)
delete renderable._renderObjects[(<RenderEntity> this._pool).id];
this._stage = null;
this.next = null;
this._renderMaterial.removeOwner(this);
this._renderMaterial = null;
this._stageElements = null;
this._materialDirty = true;
this._elementsDirty = true;
this._styleDirty = true;
this._images.length = 0;
this._samplers.length = 0;
this._uvMatrix = null;
super.onClear();
}
public _onInvalidateElements(): void {
this._elementsDirty = true;
}
public _onInvalidateMaterial(): void {
this._materialDirty = true;
this._styleDirty = true;
}
public _onInvalidateStyle(): void {
this._styleDirty = true;
}
protected _getStageElements(): _Stage_ElementsBase {
throw new AbstractMethodError();
}
protected _getRenderMaterial(): _Render_MaterialBase {
throw new AbstractMethodError();
}
protected _getStyle(): Style {
throw new AbstractMethodError();
}
/**
* //TODO
*
* @private
*/
private _updateElements(): void {
this._stageElements = this._getStageElements();
this._elementsDirty = false;
}
protected _updateMaterial(): void {
const renderMaterial: _Render_MaterialBase = this._getRenderMaterial();
if (this._renderMaterial != renderMaterial) {
if (this._renderMaterial)
this._renderMaterial.removeOwner(this);
this._renderMaterial = renderMaterial;
this._renderMaterial.addOwner(this);
}
this._materialDirty = false;
}
protected _updateStyle(): void {
const style: Style = this._getStyle();
if (this._materialDirty)
this._updateMaterial();
//create a cache of image & sampler objects for the renderable
let numImages: number = this._renderMaterial.numImages;
const material: IMaterial = this._renderMaterial.material;
this._images.length = numImages;
this._samplers.length = numImages;
const uvMatrix = style ? style.uvMatrix : material.style ? material.style.uvMatrix : null;
if (uvMatrix)
this._uvMatrix = this.stageElements.transformMatrix(this, uvMatrix);
const numTextures: number = this._renderMaterial.material.getNumTextures();
let texture: ITexture;
let index: number;
for (let i: number = 0; i < numTextures; i++) {
texture = material.getTextureAt(i);
numImages = texture.getNumImages();
for (let j: number = 0; j < numImages; j++) {
index = this._renderMaterial.getImageIndex(texture, j);
this._images[index] = this._stage.abstractions
.getAbstraction<_Stage_ImageBase>(
style?.getImageAt(texture, j)
|| this._renderMaterial.images[index]
);
this._samplers[index] = style?.getSamplerAt(texture, j)
|| this._renderMaterial.samplers[index];
}
}
this._styleDirty = false;
}
protected getDefaultMaterial(): IMaterial {
return MaterialUtils.getDefaultTextureMaterial();
}
}