@awayjs/stage
Version:
Stage for AwayJS
385 lines (290 loc) • 9.04 kB
text/typescript
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);