-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBufferArrayElement.ts
80 lines (68 loc) · 3.28 KB
/
BufferArrayElement.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { BufferElement, BufferElementParams, bytesPerSlot } from './BufferElement'
import { throwWarning } from '../../../utils/utils'
/**
* Parameters used to create a {@link BufferArrayElement}
*/
export interface BufferArrayElementParams extends BufferElementParams {
/** Initial length of the input {@link core/bindings/BufferBinding.BufferBinding#arrayBuffer | buffer binding array} */
arrayLength: number
}
/**
* Used to handle specific array {@link core/bindings/BufferBinding.BufferBinding | BufferBinding} types
*/
export class BufferArrayElement extends BufferElement {
/** Initial length of the input {@link core/bindings/BufferBinding.BufferBinding#arrayBuffer | buffer binding array} */
arrayLength: number
/** Total number of elements (i.e. {@link arrayLength} divided by {@link core/bindings/utils.BufferLayout | buffer layout} number of elements */
numElements: number
/** Number of bytes in the {@link ArrayBuffer} between two elements {@link startOffset} */
arrayStride: number
/**
* BufferArrayElement constructor
* @param parameters - {@link BufferArrayElementParams | parameters} used to create our {@link BufferArrayElement}
*/
constructor({ name, key, type = 'f32', arrayLength = 1 }: BufferArrayElementParams) {
super({ name, key, type })
this.arrayLength = arrayLength
this.numElements = this.arrayLength / this.bufferLayout.numElements
}
/**
* Get the array stride between two elements of the array, in indices
* @readonly
*/
get arrayStrideToIndex(): number {
return this.arrayStride / bytesPerSlot
}
/**
* Set the {@link core/bindings/bufferElements/BufferElement.BufferElementAlignment | alignment}
* To compute how arrays are packed, we get the second item alignment as well and use it to calculate the arrayStride between two array elements. Using the arrayStride and the total number of elements, we can easily get the end alignment position.
* @param startOffset - offset at which to start inserting the values in the {@link core/bindings/BufferBinding.BufferBinding#arrayBuffer | buffer binding array buffer}
*/
setAlignment(startOffset = 0) {
super.setAlignment(startOffset)
// repeat for a second element to know how things are laid out
const nextAlignment = this.getElementAlignment(this.getPositionAtOffset(this.endOffset + 1))
this.arrayStride = this.getByteCountBetweenPositions(this.alignment.end, nextAlignment.end)
this.alignment.end = this.getPositionAtOffset(this.endOffset + this.arrayStride * (this.numElements - 1))
}
/**
* Update the {@link view} based on the new value
* @param value - new value to use
*/
update(value) {
if (ArrayBuffer.isView(value) || Array.isArray(value)) {
let valueIndex = 0
const viewLength = this.byteCount / this.bufferLayout.View.BYTES_PER_ELEMENT
// arrayStride is our view length divided by the number of elements in our array
const stride = Math.ceil(viewLength / this.numElements)
for (let i = 0; i < this.numElements; i++) {
for (let j = 0; j < this.bufferLayout.numElements; j++) {
this.view[j + i * stride] = value[valueIndex]
valueIndex++
}
}
} else {
throwWarning(`BufferArrayElement: value passed to ${this.name} is not an array: ${value}`)
}
}
}