Skip to content

Commit

Permalink
[gltiles] factor backing data store out of DenseLayer
Browse files Browse the repository at this point in the history
  • Loading branch information
jcorbin committed Oct 18, 2023
1 parent 734831e commit da8ab9d
Showing 1 changed file with 125 additions and 78 deletions.
203 changes: 125 additions & 78 deletions gltiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export default async function makeTileRenderer(gl) {

/** Creates a minimal base tile layer.
* Caller is fully responsible for sending data to the layer buffers.
* Primarly intended to be used internally to implement specific layer data schemes.
* Primarly intended to be used internally.
*
* When stride is non-zero, each tile has an implicit x/y position relative to left/top.
*
Expand Down Expand Up @@ -280,6 +280,105 @@ export default async function makeTileRenderer(gl) {
};
},

/** Creates a simple backing data store for an array,
* where each attribute is mapped to a single array.
*
* @param {object} layer
* @param {WebGLBuffer} layer.spinBuffer
* @param {WebGLBuffer} layer.tileBuffer
* @param {() => void} layer.bind
* @param {number} [initialCapacity]
*/
makeLayerArray(layer, initialCapacity = 8) {
let dirty = true;
let cap = initialCapacity;
let spinData = new Float32Array(cap);
let tileData = new Uint16Array(cap);
const index = makeElementIndex(gl, cap);

return {
get capacity() { return cap },

get spin() { return spinData },
get tile() { return tileData },
get index() { return index },

get dirty() { return dirty },
set dirty(d) { dirty = d },

/** @param {number} n */
resize(n, copy = true) {
if (n != cap) {
cap = n;
const oldSpinData = spinData;
const oldTileData = tileData;
spinData = new Float32Array(cap);
tileData = new Uint16Array(cap);
if (copy) {
spinData.set(oldSpinData);
tileData.set(oldTileData);
}
index.resize(cap, copy);
dirty = true;
} else if (!copy) {
spinData.fill(0);
tileData.fill(0);
index.clear();
dirty = true;
}
},

clear() {
spinData.fill(0);
tileData.fill(0);
index.clear();
dirty = true;
},

send() {
gl.bindBuffer(gl.ARRAY_BUFFER, layer.spinBuffer);
gl.bufferData(gl.ARRAY_BUFFER, spinData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, layer.tileBuffer);
gl.bufferData(gl.ARRAY_BUFFER, tileData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, null);

index.send();
dirty = false;
},

bind() {
if (dirty) this.send();
viewParams.bind();
layer.bind();

// TODO spin optional
gl.enableVertexAttribArray(attrSpin);
gl.bindBuffer(gl.ARRAY_BUFFER, layer.spinBuffer);
gl.vertexAttribPointer(attrSpin, 1, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(attrLayerID);
gl.bindBuffer(gl.ARRAY_BUFFER, layer.tileBuffer);
gl.vertexAttribIPointer(attrLayerID, 1, gl.UNSIGNED_SHORT, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, null);
},

draw() {
gl.useProgram(prog);

this.bind();

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index.buffer);
gl.drawElements(gl.POINTS, index.length, index.glType, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

gl.useProgram(null);
},
};
},

// TODO more variants:
// - probably worth to make animation attributes optional;
// e.g. unanimated dense layer for static backgrounds
Expand All @@ -301,38 +400,17 @@ export default async function makeTileRenderer(gl) {
*/
makeDenseLayer({ width, height, ...params }) {
const layer = this.makeLayer({ stride: width, ...params });
const data = this.makeLayerArray(layer, width * height);

let dirty = true;
let cap = width * height;
let spinData = new Float32Array(cap);
let tileData = new Uint16Array(cap);
const index = makeElementIndex(gl, cap);

return passProperties({
const self = {
get width() { return width },
get height() { return height },

/** @param {number} w @param {number} h */
resize(w, h) {
data.resize(w * h, false);
layer.stride = w;
if (w != width || h != height) {
width = w, height = h, cap = w * h;
spinData = new Float32Array(cap);
tileData = new Uint16Array(cap);
index.resize(cap, false);
} else {
spinData.fill(0);
tileData.fill(0);
index.clear();
}
dirty = true;
},

clear() {
spinData.fill(0);
tileData.fill(0);
index.clear();
dirty = true;
width = w, height = h;
},

/** Returns a cell reference given cell absolute x/y position,
Expand All @@ -359,73 +437,42 @@ export default async function makeTileRenderer(gl) {

/** Reset all tile data to default (0 values) */
clear() {
spinData[id] = 0;
tileData[id] = 0;
index.delete(id);
dirty = true;
data.spin[id] = 0;
data.tile[id] = 0;
data.index.delete(id);
data.dirty = true;
},

/** Tile rotation in units of full turns */
get spin() { return spinData[id] },
get spin() { return data.spin[id] },
set spin(turns) {
spinData[id] = turns;
dirty = true;
data.spin[id] = turns;
data.dirty = true;
},

/** Tile texture Z index.
* FIXME "layer" id is perhaps a bad name since we're inside a Layer object anyhow. */
get layerID() { return tileData[id] },
get layerID() { return data.tile[id] },
/** Setting a value of 0, the default, will cause this tile to not be drawn. */
set layerID(layerID) {
tileData[id] = layerID;
if (layerID === 0) index.delete(id); else index.add(id);
dirty = true;
data.tile[id] = layerID;
if (layerID === 0) data.index.delete(id); else data.index.add(id);
data.dirty = true;
},
};
},

send() {
gl.bindBuffer(gl.ARRAY_BUFFER, layer.spinBuffer);
gl.bufferData(gl.ARRAY_BUFFER, spinData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, layer.tileBuffer);
gl.bufferData(gl.ARRAY_BUFFER, tileData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, null);

index.send();
dirty = false;
},

bind() {
if (dirty) this.send();
viewParams.bind();
layer.bind();

// TODO spin optional
gl.enableVertexAttribArray(attrSpin);
gl.bindBuffer(gl.ARRAY_BUFFER, layer.spinBuffer);
gl.vertexAttribPointer(attrSpin, 1, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(attrLayerID);
gl.bindBuffer(gl.ARRAY_BUFFER, layer.tileBuffer);
gl.vertexAttribIPointer(attrLayerID, 1, gl.UNSIGNED_SHORT, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, null);
},

draw() {
gl.useProgram(prog);

this.bind();

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index.buffer);
gl.drawElements(gl.POINTS, index.length, index.glType, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
};

gl.useProgram(null);
},
}, layer, 'texture', 'cellSize', 'left', 'top', 'moveTo');
return passProperties(
passProperties(self, layer,
'texture',
'cellSize',
'left', 'top', 'moveTo',
), data,
'clear',
'send', 'bind', 'draw',
);
},

};
Expand Down

0 comments on commit da8ab9d

Please sign in to comment.