104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
|
/*
|
||
|
Utility class for access and management of low-level sprite data
|
||
|
|
||
|
Maintains a single Float32Array of sprite data, keeping track of empty slots
|
||
|
to allow constant-time insertion and deletion
|
||
|
|
||
|
Automatically resizes by copying to a new, larger Float32Array when necessary,
|
||
|
or compacting into a smaller Float32Array when there's space to do so.
|
||
|
*/
|
||
|
|
||
|
import TxSprite from './tx-sprite'
|
||
|
|
||
|
export class FastVertexArray {
|
||
|
length: number;
|
||
|
count: number;
|
||
|
stride: number;
|
||
|
sprites: TxSprite[];
|
||
|
data: Float32Array;
|
||
|
freeSlots: number[];
|
||
|
lastSlot: number;
|
||
|
|
||
|
constructor (length, stride) {
|
||
|
this.length = length
|
||
|
this.count = 0
|
||
|
this.stride = stride
|
||
|
this.sprites = []
|
||
|
this.data = new Float32Array(this.length * this.stride)
|
||
|
this.freeSlots = []
|
||
|
this.lastSlot = 0
|
||
|
}
|
||
|
|
||
|
insert (sprite: TxSprite): number {
|
||
|
this.count++
|
||
|
|
||
|
let position
|
||
|
if (this.freeSlots.length) {
|
||
|
position = this.freeSlots.shift()
|
||
|
} else {
|
||
|
position = this.lastSlot
|
||
|
this.lastSlot++
|
||
|
if (this.lastSlot > this.length) {
|
||
|
this.expand()
|
||
|
}
|
||
|
}
|
||
|
this.sprites[position] = sprite
|
||
|
return position
|
||
|
}
|
||
|
|
||
|
remove (index: number): void {
|
||
|
this.count--
|
||
|
this.clearData(index)
|
||
|
this.freeSlots.push(index)
|
||
|
this.sprites[index] = null
|
||
|
if (this.length > 2048 && this.count < (this.length * 0.4)) this.compact()
|
||
|
}
|
||
|
|
||
|
setData (index: number, dataChunk: number[]): void {
|
||
|
this.data.set(dataChunk, (index * this.stride))
|
||
|
}
|
||
|
|
||
|
clearData (index: number): void {
|
||
|
this.data.fill(0, (index * this.stride), ((index+1) * this.stride))
|
||
|
}
|
||
|
|
||
|
getData (index: number): Float32Array {
|
||
|
return this.data.subarray(index, this.stride)
|
||
|
}
|
||
|
|
||
|
expand (): void {
|
||
|
this.length *= 2
|
||
|
const newData = new Float32Array(this.length * this.stride)
|
||
|
newData.set(this.data)
|
||
|
this.data = newData
|
||
|
}
|
||
|
|
||
|
compact (): void {
|
||
|
// New array length is the smallest power of 2 larger than the sprite count (but no smaller than 512)
|
||
|
const newLength = Math.max(512, Math.pow(2, Math.ceil(Math.log2(this.count))))
|
||
|
if (newLength != this.length) {
|
||
|
this.length = newLength
|
||
|
this.data = new Float32Array(this.length * this.stride)
|
||
|
let sprite
|
||
|
const newSprites = []
|
||
|
let i = 0
|
||
|
for (var index in this.sprites) {
|
||
|
sprite = this.sprites[index]
|
||
|
if (sprite) {
|
||
|
newSprites.push(sprite)
|
||
|
sprite.moveVertexPointer(i)
|
||
|
sprite.compile()
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
this.sprites = newSprites
|
||
|
this.freeSlots = []
|
||
|
this.lastSlot = i
|
||
|
}
|
||
|
}
|
||
|
|
||
|
getVertexData (): Float32Array {
|
||
|
return this.data
|
||
|
}
|
||
|
}
|