UNPKG

@awayjs/stage

Version:
385 lines (290 loc) 9.04 kB
import { AssetBase } from '@awayjs/core'; import { AttributesView } from './AttributesView'; export class AttributesBuffer extends AssetBase { public static assetType: string = '[assets AttributesBuffer]'; private _count: number = 0; private _newCount: number = 0; private _stride: number = 0; private _newStride: number = 0; private _buffer: ArrayBuffer; private _bufferView: Uint8Array; private _contentDirty: boolean; private _lengthDirty: boolean; private _viewVOs: Array<ViewVO> = new Array<ViewVO>(); /** * @returns {string} */ public get assetType(): string { return AttributesBuffer.assetType; } public get stride(): number { if (this._lengthDirty) this._updateLength(); return this._stride; } public set stride(value: number) { if (this._newStride == value) return; this._newStride = value; this.resize(); } public get count(): number { return this._newCount; } public set count(value: number) { if (this._newCount == value) return; this._newCount = value; this.resize(); } public get buffer(): ArrayBuffer { if (this._lengthDirty) this._updateLength(); this._contentDirty = false; return this._buffer; } public get bufferView(): Uint8Array { if (this._lengthDirty) this._updateLength(); this._contentDirty = false; return this._bufferView; } public set bufferView(value: Uint8Array) { this._bufferView = value; this._buffer = this._bufferView.buffer; } public get length(): number { return this._count * this.stride; } /** * */ constructor(stride: number = 0, count: number = 0) { super(); this._stride = this._newStride = stride; this._count = this._newCount = count; this._buffer = new ArrayBuffer(this._stride * this._count); this._bufferView = new Uint8Array(this._buffer, 0, this._buffer.byteLength); } /** * */ public invalidate(): void { if (this._contentDirty) return; super.invalidate(); this._contentDirty = true; } /** * * @private */ public resize(): void { if (this._lengthDirty) return; this.clear(); this._lengthDirty = true; //dispose buffer if stride is 0 if (!this._newStride) { this._buffer = null; this._bufferView = null; } } public cloneBufferView(): AttributesBuffer { const attributesBuffer: AttributesBuffer = new AttributesBuffer(this._stride, this._count); attributesBuffer.bufferView.set(this.bufferView); return attributesBuffer; } public clone(): AttributesBuffer { const attributesBuffer: AttributesBuffer = new AttributesBuffer(this._stride, this._count); attributesBuffer.bufferView.set(this.bufferView); const len: number = this._viewVOs.length; for (let i: number = 0; i < len; i++) this._viewVOs[i].view._internalClone(attributesBuffer); return attributesBuffer; } public getView(index: number): AttributesView { if (index < this._viewVOs.length) return this._viewVOs[index].view; return null; } public _setAttributes(viewIndex: number, arrayBufferView: ArrayBufferView, offset: number = 0): void { const array: Uint8Array = (arrayBufferView instanceof Uint8Array) ? <Uint8Array> arrayBufferView : new Uint8Array(arrayBufferView.buffer); const viewVO: ViewVO = this._viewVOs[viewIndex]; const vLength: number = viewVO.length; const vOffset: number = viewVO.offset; const vCount: number = array.length / vLength; //make sure there is enough space in the buffer if (this.count < vCount + offset) this.count = vCount + offset; if (this._lengthDirty) this._updateLength(); //fast path for separate buffers if (this._viewVOs.length == 1) { this._bufferView.set(array); } else { for (let i = 0; i < vCount; i++) { this._bufferView.set( array.subarray(i * vLength, (i + 1) * vLength), (i + offset) * this._stride + vOffset); } } this.invalidate(); } public _addView(view: AttributesView): void { const viewVO: ViewVO = new ViewVO(view); const len: number = this._viewVOs.length; viewVO.offset = len ? this._viewVOs[len - 1].offset + this._viewVOs[len - 1].length : 0; this._viewVOs.push(viewVO); if (this._newStride < viewVO.offset + viewVO.length) { this._newStride = viewVO.offset + viewVO.length; this.resize(); } view._index = len; } public _removeView(view: AttributesView): void { const viewIndex: number = view._index; let viewVO: ViewVO = this._viewVOs.splice(viewIndex, 1)[0]; const len: number = this._viewVOs.length; viewVO.dispose(); for (let i: number = viewIndex; i < len; i++) { viewVO = this._viewVOs[i]; viewVO.offset = i ? this._viewVOs[i - 1].offset + this._viewVOs[i - 1].length : 0; viewVO.view._index = i; } this._newStride = len ? this._viewVOs[len - 1].offset + this._viewVOs[len - 1].length : 0; this.resize(); } public _getOffset(viewIndex: number): number { return this._viewVOs[viewIndex].offset; } public _updateLength(): void { this._lengthDirty = false; let i: number; let j: number; const len: number = this._viewVOs.length; const newLength: number = this._newStride * this._newCount; if (!this._buffer || this._buffer.byteLength != newLength) { const newBuffer: ArrayBuffer = new ArrayBuffer(newLength); const newView: Uint8Array = new Uint8Array(newBuffer, 0, newBuffer.byteLength); let viewVO: ViewVO; let vLength: number; let vOffset: number; let vOldOffset: number; if (this._buffer) { if (this._stride != this._newStride) { for (i = 0; i < len; i++) { viewVO = this._viewVOs[i]; vLength = viewVO.length; vOffset = viewVO.offset; vOldOffset = viewVO.oldOffset; for (j = 0; j < this._count; j++) { if (vOldOffset != null) { newView.set( new Uint8Array( this._buffer, j * this._stride + vOldOffset, vLength), j * this._newStride + vOffset); } } viewVO.oldOffset = viewVO.offset; } this._stride = this._newStride; } else { //TODO: bypass quantisation of bytearray on instantiation newView.set(new Uint8Array(this._buffer, 0, Math.min(newLength, this._buffer.byteLength))); } } this._buffer = newBuffer; this._bufferView = newView; } this._count = this._newCount; } } class ViewVO { public view: AttributesView; public length; public offset; public oldOffset; constructor(view: AttributesView) { this.view = view; this.length = view.size * view.dimensions; } public dispose(): void { this.view = null; } public clone(): ViewVO { return new ViewVO(this.view); } } import { AssetEvent, AbstractionBase } from '@awayjs/core'; import { IIndexBuffer } from '../base/IIndexBuffer'; import { IVertexBuffer } from '../base/IVertexBuffer'; import { ContextGLDrawMode } from '../base/ContextGLDrawMode'; import { Stage } from '../Stage'; /** * * @class away.pool._Stage_AttributesBuffer */ export class _Stage_AttributesBuffer extends AbstractionBase { public _indexBuffer: IIndexBuffer; public _vertexBuffer: IVertexBuffer; public _stage: Stage; public _attributesBuffer: AttributesBuffer; public _mipmap: boolean; public init(attributesBuffer: AttributesBuffer, stage: Stage): void { super.init(attributesBuffer, stage); this._stage = stage; this._attributesBuffer = attributesBuffer; } /** * */ public onClear(event: AssetEvent): void { super.onClear(event); this._attributesBuffer = null; if (this._indexBuffer) { this._indexBuffer.dispose(); this._indexBuffer = null; } if (this._vertexBuffer) { this._vertexBuffer.dispose(); this._vertexBuffer = null; } } public activate(index: number, size: number, dimensions: number, offset: number, unsigned: boolean = false): void { this._stage.setVertexBuffer(index, this._getVertexBuffer(), size, dimensions, offset, unsigned); } public draw(mode: ContextGLDrawMode, firstIndex: number, numIndices: number): void { this._stage.context.drawIndices(mode, this._getIndexBuffer(), firstIndex, numIndices); } public _getIndexBuffer(): IIndexBuffer { if (!this._indexBuffer) { this._invalid = true; this._indexBuffer = this._stage.context.createIndexBuffer( this._attributesBuffer.count * this._attributesBuffer.stride / 2); //hardcoded assuming UintArray } if (this._invalid) { this._invalid = false; this._indexBuffer.uploadFromByteArray(this._attributesBuffer.buffer, 0, this._attributesBuffer.length); } return this._indexBuffer; } public _getVertexBuffer(): IVertexBuffer { if (!this._vertexBuffer) { this._invalid = true; this._vertexBuffer = this._stage.context.createVertexBuffer( this._attributesBuffer.count, this._attributesBuffer.stride); } if (this._invalid) { this._invalid = false; this._vertexBuffer.uploadFromByteArray(this._attributesBuffer.buffer, 0, this._attributesBuffer.count); } return this._vertexBuffer; } } Stage.registerAbstraction(_Stage_AttributesBuffer, AttributesBuffer);