@sveltejs/gl
Version:
A (very experimental) project to bring WebGL to Svelte
134 lines (104 loc) • 2.93 kB
JavaScript
class GeometryInstance {
constructor(scene, program, attributes, index, primitive, count) {
this.scene = scene;
const gl = scene.gl;
this.attributes = attributes;
this.index = index;
this.primitive = primitive;
this.count = count;
this.locations = {};
this.buffers = {};
for (const key in attributes) {
const attribute = attributes[key];
this.locations[key] = gl.getAttribLocation(program, key);
const buffer = gl.createBuffer();
this.buffers[key] = buffer;
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, attribute.data, attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
}
if (index) {
const buffer = gl.createBuffer();
this.buffers.__index = buffer;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);
}
}
set_attributes(gl) {
for (const key in this.attributes) {
const attribute = this.attributes[key];
const loc = this.locations[key];
if (loc < 0) continue; // attribute is unused by current program
const {
size = 3,
type = gl.FLOAT,
normalized = false,
stride = 0,
offset = 0
} = attribute;
// Bind the position buffer.
const buffer = this.buffers[key];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// Turn on the attribute
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(
loc,
size,
type,
normalized,
stride,
offset
);
}
}
update(k, data, count) {
const scene = this.scene;
const { gl } = scene;
const attribute = this.attributes[k];
const buffer = this.buffers[k];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, attribute.data = data, attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
this.count = count;
if (count === Infinity) {
throw new Error(`GL.Geometry must be instantiated with one or more { data, size } attributes`);
}
scene.invalidate();
}
}
export default class Geometry {
constructor(attributes = {}, opts = {}) {
this.attributes = attributes;
const { index, primitive = 'TRIANGLES' } = opts;
this.index = index;
this.primitive = primitive.toUpperCase();
this.count = get_count(attributes);
this.instances = new Map();
}
instantiate(scene, program) {
if (!this.instances.has(program)) {
this.instances.set(program, new GeometryInstance(
scene,
program,
this.attributes,
this.index,
this.primitive,
this.count
));
}
return this.instances.get(program);
}
update(k, data) {
this.attributes[k].data = data;
this.count = get_count(this.attributes);
this.instances.forEach(instance => {
instance.update(k, data, this.count);
});
}
}
function get_count(attributes) {
let min = Infinity;
for (const k in attributes) {
const count = attributes[k].data.length / attributes[k].size;
if (count < min) min = count;
}
return min;
}