Created
November 8, 2023 10:19
-
-
Save learosema/5f075982d271fa2b4dea862e8a25d9e4 to your computer and use it in GitHub Desktop.
Uniform struct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { UniformStruct } from "./uniform-struct"; | |
describe('UniformStruct', () => { | |
it('should create an empty buffer and data structure by default', () => { | |
const us = new UniformStruct(); | |
expect(us.buffer).toBeInstanceOf(ArrayBuffer); | |
expect(us.buffer.byteLength).toBe(0); | |
expect(us.data).toStrictEqual({}); | |
}); | |
it('should hold numeric data in the buffer',() => { | |
const us = new UniformStruct(); | |
us.data.vector = [1,2,3]; | |
expect(us.buffer).toStrictEqual(Float32Array.from([1, 2, 3]).buffer); | |
expect(us.buffer.byteLength).toEqual(3 * 4); | |
}); | |
it('should be able to initialize a data structure in the constructor', () => { | |
const us = new UniformStruct({ | |
aVector: [1,2,3], | |
roughlyPi: 22 / 7, | |
aNumber: 4, | |
}); | |
expect(us.buffer).toStrictEqual( | |
Float32Array.from([1,2,3, 22 / 7, 4]).buffer | |
); | |
expect(us.buffer.byteLength).toEqual(5 * 4); | |
}); | |
it('should be able to modify data inside the structure', () => { | |
const us = new UniformStruct({ | |
arbitraryVector: [1,2,3], | |
roughlyPi: 22 / 7, | |
arbitraryNumber: 4 | |
}); | |
us.data.arbitraryNumber = 42; | |
us.data.arbitraryVector = [4, 5, 6]; | |
expect(us.buffer).toStrictEqual( | |
Float32Array.from([4, 5, 6, 22 / 7, 42]).buffer | |
); | |
}); | |
it('should be able to add properties inside the structure', () => { | |
const us = new UniformStruct({ | |
arbitraryVector: [1,2,3], | |
roughlyPi: 22 / 7, | |
arbitraryNumber: 42 | |
}); | |
us.data.anotherNumber = 666; | |
expect(us.buffer).toStrictEqual( | |
Float32Array.from([1,2,3, 22 / 7, 42, 666]).buffer | |
); | |
}); | |
it('should be able to add int (i32) properties', () => { | |
const us = new UniformStruct(); | |
us.data.intNumber = 42; | |
expect(us.buffer).toStrictEqual( | |
new Int32Array([42]).buffer | |
); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type UniformStructData = Record<string, number|Iterable<number>>; | |
/** | |
* UniformStruct provides a C-like "struct" | |
* which is synchronized to an array buffer. | |
*/ | |
export class UniformStruct { | |
public buffer = new ArrayBuffer(0); | |
public typedArrays: Record<string, Float32Array|Int32Array> = {} | |
public data: UniformStructData; | |
#internalData: Record<string, number|Iterable<number>> = {}; | |
constructor(initialData ?: UniformStructData) { | |
this.#internalData = Object.assign({}, initialData || {}); | |
this.#createBuffer(); | |
const self = this; | |
this.data = new Proxy<Record<string, number|Iterable<number>>>( | |
this.#internalData, { | |
set(target: Record<string, any>, key: string, value: any) { | |
const result = Reflect.set(target, key, value); | |
if (!self.typedArrays.hasOwnProperty(key)) { | |
self.#createBuffer(); | |
} else { | |
self.typedArrays[key].set( | |
value instanceof Array ? value : [value] | |
); | |
} | |
return result; | |
} | |
}); | |
} | |
#createBuffer() { | |
let pointer = 0; | |
const offsets: Record<string, number> = {}; | |
for (const [key, val] of Object.entries(this.#internalData)) { | |
const count = (val instanceof Array) ? val.length : 1; | |
offsets[key] = pointer; | |
const itemSize = 4; | |
pointer += count * itemSize; | |
} | |
this.buffer = new ArrayBuffer(pointer); | |
this.typedArrays = {}; | |
for (const [key, val] of (Object.entries(this.#internalData))) { | |
const offset = offsets[key]; | |
const count = (val instanceof Array) ? val.length : 1; | |
const typedArray = key.startsWith('int') ? | |
new Int32Array(this.buffer, offset, count) : | |
new Float32Array(this.buffer, offset, count); | |
typedArray.set(val instanceof Array ? val: [val]); | |
this.typedArrays[key] = typedArray; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment