Skip to content

Commit

Permalink
[gldemo] allow tile position data to be animated
Browse files Browse the repository at this point in the history
  • Loading branch information
jcorbin committed Oct 14, 2023
1 parent 88e565a commit 8f037e6
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
62 changes: 62 additions & 0 deletions gltiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ export default async function makeTileRenderer(gl) {
const uniSheet = mustGetUniform('sheet'); // sampler2D

const attrPos = mustGetAttr('pos'); // vec4: xy=offset, z=spin, w=scale
const attrPosTo = mustGetAttr('pos_to'); // vec4: xy=offset, z=spin, w=scale
const attrAnim = mustGetAttr('anim'); // vec3: x=start_time, y=duration, z=mode

const attrLayerID = mustGetAttr('layerID'); // int

const perspectiveUniform = viewParams.getVar('perspective');
Expand Down Expand Up @@ -246,10 +249,14 @@ export default async function makeTileRenderer(gl) {
// - sub-region invalidation to avoid recopying old data / only copy new data

const posBuffer = gl.createBuffer();
const posToBuffer = gl.createBuffer();
const animBuffer = gl.createBuffer();
const tileBuffer = gl.createBuffer();

const cap = width * height;
const posData = new Float32Array(cap * 4);
const posToData = new Float32Array(cap * 4);
const animData = new Float32Array(cap * 3);
const tileData = new Uint16Array(cap);
const index = makeElementIndex(gl, cap);

Expand Down Expand Up @@ -281,11 +288,28 @@ export default async function makeTileRenderer(gl) {
* @param {{x: number, y: number}} [data.offset]
* @param {number} [data.spin]
* @param {number} [data.scale]
*
* @param {{x: number, y: number}} [data.offsetTo]
* @param {number} [data.spinTo]
* @param {number} [data.scaleTo]
* `
* @param {number} [data.animStart]
* @param {number} [data.animDuration]
* @param {"once"|"loop"|"loopback"} [data.animMode]
*/
set(x, y, {
layerID,
offset = { x: 0, y: 0 }, spin = 0, scale = 1,
offsetTo = { x: 0, y: 0 }, spinTo = 0, scaleTo = 1,
animStart = 0, animDuration = 0, animMode = 'once'
}) {
const animCode =
animMode == 'once' ? 0 :
animMode == 'loop' ? 1 :
animMode == 'loopback' ? 2 : null;
if (animCode == null)
throw new Error('invalid animMode');

if (x < 0 || y < 0 || x >= width || y >= height)
throw new Error(`point: ${JSON.stringify({ x, y })} outside of layer bounds: ${JSON.stringify({ width, height })}`);
const id = Math.floor(y - top) * width + Math.floor(x - left);
Expand All @@ -296,6 +320,15 @@ export default async function makeTileRenderer(gl) {
posData[4 * id + 2] = spin;
posData[4 * id + 3] = scale;

posToData[4 * id + 0] = offsetTo.x;
posToData[4 * id + 1] = offsetTo.y;
posToData[4 * id + 2] = spinTo;
posToData[4 * id + 3] = scaleTo;

animData[3 * id + 0] = animStart;
animData[3 * id + 1] = animDuration;
animData[3 * id + 2] = animCode;

if (layerID === 0) index.delete(id);
else index.add(id);
},
Expand All @@ -315,16 +348,37 @@ export default async function makeTileRenderer(gl) {
const spin = posData[4 * id + 2];
const scale = posData[4 * id + 3];

const offsetToX = posToData[4 * id + 0];
const offsetToY = posToData[4 * id + 1];
const spinTo = posToData[4 * id + 2];
const scaleTo = posToData[4 * id + 3];

const animStart = animData[3 * id + 0];
const animDuration = animData[3 * id + 1];
const animCode = animData[3 * id + 2];
const animMode =
animCode == 0 ? 'once' :
animCode == 1 ? 'loop' :
animCode == 2 ? 'loopback' : 'invalid';

return {
layerID,
offset: { x: offsetX, y: offsetY }, spin, scale,
offsetTo: { x: offsetToX, y: offsetToY }, spinTo, scaleTo,
animStart, animDuration, animMode
};
},

send() {
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
gl.bufferData(gl.ARRAY_BUFFER, posData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, posToBuffer);
gl.bufferData(gl.ARRAY_BUFFER, posToData, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, animBuffer);
gl.bufferData(gl.ARRAY_BUFFER, animData, gl.STATIC_DRAW);

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

Expand Down Expand Up @@ -352,6 +406,14 @@ export default async function makeTileRenderer(gl) {
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
gl.vertexAttribPointer(attrPos, 4, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(attrPosTo);
gl.bindBuffer(gl.ARRAY_BUFFER, posToBuffer);
gl.vertexAttribPointer(attrPosTo, 4, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(attrAnim);
gl.bindBuffer(gl.ARRAY_BUFFER, animBuffer);
gl.vertexAttribPointer(attrAnim, 3, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(attrLayerID);
gl.bindBuffer(gl.ARRAY_BUFFER, tileBuffer);
gl.vertexAttribIPointer(attrLayerID, 1, gl.UNSIGNED_SHORT, 0, 0);
Expand Down
28 changes: 28 additions & 0 deletions gltiles.vert
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ uniform LayerParams {
in uint layerID;

in vec4 pos;
in vec4 pos_to;
in vec3 anim; // x=start_time, y=duration, z=mode

out float sheetLayer;
out mat3 tileTransform;
Expand All @@ -54,6 +56,32 @@ const mat3 spinOffset = mat3(
);

void main(void) {
vec4 pos_at = pos;

if (anim_enabled && anim.y > 0.0) {
float a = (anim_time - anim.x) / anim.y;
if (a > 0.0) {
switch (int(anim.z)) {

case 1: // loop
a = fract(a);
break;

case 2: // loop-back
if (int(floor(a)) % 2 == 1) {
a = 1.0 - fract(a);
} else {
a = fract(a);
}
break;

default:
a = max(0.0, min(1.0, a));
}
pos_at = mix(pos_at, pos_to, /*a*/ 0.0);
}
}

vec2 offset = pos.xy;
float spin = pos.z;
float scale = pos.w;
Expand Down

0 comments on commit 8f037e6

Please sign in to comment.