133 lines
3.6 KiB
JavaScript
133 lines
3.6 KiB
JavaScript
export class Accessor {
|
|
|
|
constructor({
|
|
buffer,
|
|
viewLength,
|
|
viewOffset = 0,
|
|
offset = 0,
|
|
stride = componentSize,
|
|
|
|
componentType = 'int',
|
|
componentCount = 1,
|
|
componentSize = 1,
|
|
componentSigned = false,
|
|
componentNormalized = false,
|
|
} = {}) {
|
|
this.buffer = buffer;
|
|
this.offset = offset;
|
|
this.stride = stride;
|
|
|
|
this.componentType = componentType;
|
|
this.componentCount = componentCount;
|
|
this.componentSize = componentSize;
|
|
this.componentSigned = componentSigned;
|
|
this.componentNormalized = componentNormalized;
|
|
|
|
const viewType = this.getViewType({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
});
|
|
|
|
if (viewLength !== undefined) {
|
|
this.view = new viewType(buffer, viewOffset, viewLength / viewType.BYTES_PER_ELEMENT);
|
|
} else {
|
|
this.view = new viewType(buffer, viewOffset);
|
|
}
|
|
|
|
this.offsetInElements = offset / viewType.BYTES_PER_ELEMENT;
|
|
this.strideInElements = stride / viewType.BYTES_PER_ELEMENT;
|
|
|
|
this.count = Math.floor((this.view.length - this.offsetInElements) / this.strideInElements);
|
|
|
|
this.normalize = this.getNormalizer({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
componentNormalized,
|
|
});
|
|
|
|
this.denormalize = this.getDenormalizer({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
componentNormalized,
|
|
});
|
|
}
|
|
|
|
get(index) {
|
|
const start = index * this.strideInElements + this.offsetInElements;
|
|
const end = start + this.componentCount;
|
|
return [...this.view.slice(start, end)].map(this.normalize);
|
|
}
|
|
|
|
set(index, value) {
|
|
const start = index * this.strideInElements + this.offsetInElements;
|
|
this.view.set(value.map(this.denormalize), start);
|
|
}
|
|
|
|
getNormalizer({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
componentNormalized,
|
|
}) {
|
|
if (!componentNormalized || componentType === 'float') {
|
|
return x => x;
|
|
}
|
|
|
|
const multiplier = componentSigned
|
|
? 2 ** ((componentSize * 8) - 1) - 1
|
|
: 2 ** (componentSize * 8) - 1;
|
|
|
|
return x => Math.max(x / multiplier, -1);
|
|
}
|
|
|
|
getDenormalizer({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
componentNormalized,
|
|
}) {
|
|
if (!componentNormalized || componentType === 'float') {
|
|
return x => x;
|
|
}
|
|
|
|
const multiplier = componentSigned
|
|
? 2 ** ((componentSize * 8) - 1) - 1
|
|
: 2 ** (componentSize * 8) - 1;
|
|
|
|
const min = componentSigned ? -1 : 0;
|
|
const max = 1;
|
|
|
|
return x => Math.floor(0.5 + multiplier * Math.min(Math.max(x, min), max));
|
|
}
|
|
|
|
getViewType({
|
|
componentType,
|
|
componentSize,
|
|
componentSigned,
|
|
}) {
|
|
if (componentType === 'float') {
|
|
if (componentSize === 4) {
|
|
return Float32Array;
|
|
}
|
|
} else if (componentType === 'int') {
|
|
if (componentSigned) {
|
|
switch (componentSize) {
|
|
case 1: return Int8Array;
|
|
case 2: return Int16Array;
|
|
case 4: return Int32Array;
|
|
}
|
|
} else {
|
|
switch (componentSize) {
|
|
case 1: return Uint8Array;
|
|
case 2: return Uint16Array;
|
|
case 4: return Uint32Array;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|