Skip to content

Commit

Permalink
add support for partial uniform paths
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Sep 27, 2021
1 parent 7d840f7 commit 81fef12
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 44 deletions.
74 changes: 32 additions & 42 deletions src/programs.js
Original file line number Diff line number Diff line change
Expand Up @@ -869,18 +869,20 @@ function isBuiltIn(info) {

const tokenRE = /(?=[.[\]])|(?<=[.[\]])/g;
const isDigit = s => s >= '0' && s <= '9';
function addSetterToUniformTree(path, setter, node) {
const tokens = path.split(tokenRE);
function addSetterToUniformTree(fullPath, setter, node, uniformSetters) {
const tokens = fullPath.split(tokenRE);
let tokenNdx = 0;
let path = '';

for (;;) {
const token = tokens[tokenNdx++]; // has to be name or number
path += token;
const isArrayIndex = isDigit(token[0]);
const accessor = isArrayIndex
? parseInt(token)
: token;
if (isArrayIndex) {
++tokenNdx; // skip ']'
path += tokens[tokenNdx++]; // skip ']'
}
const isLastToken = tokenNdx === tokens.length;
if (isLastToken) {
Expand All @@ -892,11 +894,16 @@ function addSetterToUniformTree(path, setter, node) {
const child = node[accessor] || (isArray ? [] : {});
node[accessor] = child;
node = child;
uniformSetters[path] = uniformSetters[path] || function(node) {
return function(value) {
setUniformTree(node, value);
};
}(child);
path += token;
}
}
}


/**
* Creates setter functions for all uniforms of a shader
* program.
Expand All @@ -908,7 +915,7 @@ function addSetterToUniformTree(path, setter, node) {
* @returns {Object.<string, function>} an object with a setter by name for each uniform
* @memberOf module:twgl/programs
*/
function createUniformSettersAndUniformTree(gl, program) {
function createUniformSetters(gl, program) {
let textureUnit = 0;

/**
Expand Down Expand Up @@ -965,25 +972,10 @@ function createUniformSettersAndUniformTree(gl, program) {
if (location) {
const setter = createUniformSetter(program, uniformInfo, location);
uniformSetters[name] = setter;
addSetterToUniformTree(name, setter, uniformTree);
addSetterToUniformTree(name, setter, uniformTree, uniformSetters);
}
}
return { uniformSetters, uniformTree };
}

/**
* Creates setter functions for all uniforms of a shader
* program.
*
* @see {@link module:twgl.setUniforms}
*
* @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {WebGLProgram} program the program to create setters for.
* @returns {Object.<string, function>} an object with a setter by name for each uniform
* @memberOf module:twgl/programs
*/
function createUniformSetters(gl, program) {
const {uniformSetters} = createUniformSettersAndUniformTree(gl, program);
return uniformSetters;
}

Expand Down Expand Up @@ -1295,7 +1287,7 @@ function createUniformBlockInfoFromProgram(gl, program, uniformBlockSpec, blockN
// solution.
const setter = createUniformBlockUniformSetter(uniformView, isArray, typeInfo.rows, typeInfo.cols);
setters[name] = setter;
addSetterToUniformTree(name, setter, setterTree);
addSetterToUniformTree(name, setter, setterTree, setters);
});
return {
name: blockName,
Expand All @@ -1304,7 +1296,6 @@ function createUniformBlockInfoFromProgram(gl, program, uniformBlockSpec, blockN
buffer,
uniforms,
setters,
setterTree,
};
}

Expand Down Expand Up @@ -1433,6 +1424,14 @@ function setUniformBlock(gl, programInfo, uniformBlockInfo) {
* "lights[1].color": [0, 0, 1, 1],
* });
*
* You can also specify partial paths
*
* twgl.setBlockUniforms(someBlockInfo, {
* 'lights[1]: { intensity: 5.0, color: [1, 0, 0, 1] },
* });
*
* But you can not specify leaf array indices.
*
* **IMPORTANT!**, packing in a UniformBlock is unintuitive.
* For example the actual layout of `someVec3Array` above in memory
* is `1, 2, 3, unused, 4, 5, 6, unused`. twgl takes in 6 values
Expand All @@ -1449,19 +1448,11 @@ function setUniformBlock(gl, programInfo, uniformBlockInfo) {
*/
function setBlockUniforms(uniformBlockInfo, values) {
const setters = uniformBlockInfo.setters;
const setterTree = uniformBlockInfo.setterTree;
for (const name in values) {
const setter = setters[name];
if (setter) {
const value = values[name];
setter(value);
} else {
// NOTE: I'm not totally happy that there are 2 paths
// here but I didn't want to change the API.
const treeSetter = setterTree[name];
if (treeSetter) {
setUniformTree(treeSetter, values[name]);
}
}
}
}
Expand Down Expand Up @@ -1608,7 +1599,7 @@ function setUniformTree(tree, values) {
* ],
* });
*
* // or the more traditional way
* or the more traditional way
*
* twgl.setUniforms(programInfo, {
* "lights[0].intensity": 5.0,
Expand All @@ -1617,11 +1608,18 @@ function setUniformTree(tree, values) {
* "lights[1].color": [0, 0, 1, 1],
* });
*
* You can also specify partial paths
*
* twgl.setUniforms(programInfo, {
* 'lights[1]: { intensity: 5.0, color: [1, 0, 0, 1] },
* });
*
* But you can not specify leaf array indices
*
* @memberOf module:twgl/programs
*/
function setUniforms(setters, ...args) { // eslint-disable-line
const actualSetters = setters.uniformSetters || setters;
const tree = setters.uniformTree;
const numArgs = args.length;
for (let aNdx = 0; aNdx < numArgs; ++aNdx) {
const values = args[aNdx];
Expand All @@ -1635,13 +1633,6 @@ function setUniforms(setters, ...args) { // eslint-disable-line
const setter = actualSetters[name];
if (setter) {
setter(values[name]);
} else if (tree) {
// NOTE: I'm not totally happy that there are 2 paths
// here but I didn't want to change the API.
const treeSetter = tree[name];
if (treeSetter) {
setUniformTree(treeSetter, values[name]);
}
}
}
}
Expand Down Expand Up @@ -1827,13 +1818,12 @@ function setBuffersAndAttributes(gl, programInfo, buffers) {
* @memberOf module:twgl/programs
*/
function createProgramInfoFromProgram(gl, program) {
const {uniformSetters, uniformTree} = createUniformSettersAndUniformTree(gl, program);
const uniformSetters = createUniformSetters(gl, program);
const attribSetters = createAttributeSetters(gl, program);
const programInfo = {
program,
uniformSetters,
attribSetters,
uniformTree,
};

if (utils.isWebGL2(gl)) {
Expand Down
31 changes: 29 additions & 2 deletions test/tests/program-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ describe('program tests', () => {
assertEqual(gl.getError(), gl.NONE);
});

it('test uniform tree', () => {
it('test uniform struct/array', () => {
const {gl} = createContext();

gl.canvas.width = 1;
Expand Down Expand Up @@ -317,9 +317,30 @@ describe('program tests', () => {
});
gl.drawArrays(gl.POINTS, 0, 1);
checkColor(gl, [21, 42, 63, 44]);

twgl.setUniforms(programInfo, {
'lights[0].extra': [
{ v4: [1, 2, 3, 4], },
],
'lights[1].intensity': 100,
});
gl.drawArrays(gl.POINTS, 0, 1);
checkColor(gl, [111, 122, 133, 104]);

/*
TWGL does not currently support
setting random elements of leaf
arrays
twgl.setUniforms(programInfo, {
'lights[0].nearFar[1]': 1000,
});
checkColor(gl, [111, 1022, 133, 104]);
*/

});

itWebGL2('test uniformblock tree', () => {
itWebGL2('test uniformblock struct/array', () => {
const {gl} = createContext2();

const vs = `#version 300 es
Expand Down Expand Up @@ -424,6 +445,12 @@ describe('program tests', () => {
0, // padding
]);
assertArrayEqual(uboInfo.asFloat, expected);

twgl.setBlockUniforms(uboInfo, {
'lights[1].extra[1]': { v4: [301, 302, 303, 304] },
});
expected.set([301, 302, 303, 304], expected.indexOf(217));
assertArrayEqual(uboInfo.asFloat, expected);
});

});

0 comments on commit 81fef12

Please sign in to comment.