-
Notifications
You must be signed in to change notification settings - Fork 329
Description
I may be missing some information here but i'm looking for a best pattern to define commands.
I would like to define regl draw commands as stand alone modules and import them as needed like:
import regl from './regl';
import flatVert from '../dsl/render/shaders/flat.vert';
import flatFrag from '../dsl/render/shaders/flat.frag';
export default regl({
vert: flatVert,
frag: flatFrag,
elements: regl.prop('cells'),
attributes: {
position: regl.prop('positions'),
},
uniforms: {
color: regl.prop('color'),
model: regl.prop('model')
}
});
This however is not possible with the current wrapREGL
interface design. Because the default export of the regl module is actually the wrapREGL
function, you need to first execute wrapRegl
before getting a regl instance to defining any commands or resources:
import reglInit from 'regl';
const regl = reglInit({
gl,
extensions: ['oes_texture_half_float'],
});
const drawFlat = regl({
vert: flatVert,
frag: flatFrag,
elements: this.regl.prop('cells'),
attributes: {
position: this.regl.prop('positions'),
},
uniforms: {
color: this.regl.prop('color'),
model: this.regl.prop('model')
}
});
This means in order to define standalone modules for the draw commands you need to first execute wrapREGL
to get a reference to the actual regl instance and then some how pass that into the standalone modules you need a wrapper function and mskes things a bit awkward
// drawFlat.js
import flatVert from '../dsl/render/shaders/flat.vert';
import flatFrag from '../dsl/render/shaders/flat.frag';
export default function(regl){
return regl({
vert: flatVert,
frag: flatFrag,
elements: regl.prop('cells'),
attributes: {
position: regl.prop('positions'),
},
uniforms: {
color: regl.prop('color'),
model: regl.prop('model')
}
})
}
// main drawing app.js
import reglInit from 'regl';
import DrawFlat from 'drawFlat.js'
const regl = reglInit({
gl,
extensions: ['oes_texture_half_float'],
});
const drawFlat = DrawFlat(regl);
In order to achieve the individual module pattern I outlined in the first example, I have hacked together a helper library I'm calling reglDefer
. Its usuage looks like this:
import regl from './reglDefer.js';
import flatVert from '../dsl/render/shaders/flat.vert';
import flatFrag from '../dsl/render/shaders/flat.frag';
export default regl({
vert: flatVert,
frag: flatFrag,
elements: regl.prop('cells'),
attributes: {
position: regl.prop('positions'),
},
uniforms: {
color: regl.prop('color'),
model: regl.prop('model')
}
});
reglDefer
is a meta library that lets you define regl commands and regl.props
before regl is initalized and queues them up. Once a 'live' regl instance is registered it will flush the queues and initalize all the pending resource and command registration. Here is the reglDefer
implementation:
import uuidv1 from 'uuid/v1';
const deferredMethods = {};
const deferredDefs = {};
let realRegl = null;
let reglDefer = function(reglDefinition){
if(realRegl) return realRegl(reglDefinition);
const callId = `defer-${uuidv1()}`;
deferredDefs[callId] = reglDefinition
return function(){
return deferredDefs[callId](...arguments);
}
};
['prop'].forEach((method) => {
reglDefer[method] = function(){
const args = [...arguments];
if(realRegl) return realRegl[method](args);
const callId = `defer-${uuidv1()}`;
deferredMethods[callId] = [method, args]
return callId;
}
});
reglDefer.init = function(initalizedRegl){
realRegl = initalizedRegl;
Object.entries(deferredMethods).forEach(([callId, [method, args]]) => {
deferredMethods[callId] = realRegl[method](args);
});
// recurse over the regl draw definition and replace any deffered props
function replaceMethods(acc, key){
if(deferredMethods[acc[key]]){
acc[key] = deferredMethods[acc[key]]
return acc
}
if(typeof acc[key] === 'object'){
acc[key] = Object.keys(acc[key]).reduce(replaceMethods, acc[key])
return acc;
}
acc[key] = acc[key];
return acc;
}
Object.entries(deferredDefs).forEach(([key, definition]) => {
deferredDefs[key] = Object.keys(definition).reduce(replaceMethods, definition);
deferredDefs[key] = realRegl(deferredDefs[key]);
});
};
export default reglDefer;
Please let me know if this is insane and I missed an already existing pattern for handling this. I'm curious how others are handling command definition. Am I missing some functionality that wrapREGL
handles?