For as long as I have been working with Gladius, the loading of the meshes and materials has bugged me. Don't get me wrong, they are definitely handy for handling large systems, but most of the things that I will do in Gaming JavaScript will be of the simpler variety.
My simple avatar requires three meshes (shapes) and two colors (materials):
Currently, this requires external mesh and materials to be loaded via a Gladius
engine.get()
: // Mesh and material resources
var resources = {};
engine.get(
[
{
type: engine["gladius-cubicvr"].Mesh,
url: 'assets/procedural-primitive-mesh.js?type=sphere&radius=1',
load: engine.loaders.procedural,
onsuccess: function(mesh) {
resources.sphere_mesh = mesh;
},
onfailure: function(error) {console.log(error);}
},
// Other meshes ...
{
type: engine["gladius-cubicvr"].MaterialDefinition,
url: 'assets/rgb-material.js?r=255',
load: engine.loaders.procedural,
onsuccess: function(material) {
resources.red_material = material;
},
onfailure: function(error) {}
},
// Other materials ...
],
{
oncomplete: game.bind(null, engine, resources)
}
);
There is very little actual mesh and material definition going on in that code. The type
specifies Mesh
or MaterialDefinition
and the query string some options. Everything else in there is ceremony built around loading these external "procedural" scripts.The
procedural-primitive-mesh.js
is responsible for no more than taking the query parameter strings and returning an appropriate options hash:function proc(options) { return { primitive: options, compile: true }; }It turns out that the returned options hash is "appropriate" as an argument for an object constructor. Specifically these options hashes are used for
Mesh
and MaterialDefinition
objects.So, instead of all of the procedural loader ceremony, I can create a new sphere like:
new engine["gladius-cubicvr"].Mesh({ primitive: { type: 'sphere' }, compile: true })Looking at that constructor, I really only need one argument: the "sphere" type. So I create a factory function that will generate primitive types with an optional second
options
hash argument: function primitiveMesh(type, options) {
var Mesh = engine["gladius-cubicvr"].Mesh;
options = options || {};
options.type = type;
return new Mesh({primitives: options, compile: true});
}
Using that, I can reduce all of the meshes that are used to build my avatar down to: var resources = {
sphere_mesh: primitiveMesh('sphere'),
cone_mesh: primitiveMesh('cone', {height: 2, base: 2}),
cylinder_mesh: primitiveMesh('cylinder', {radius: 0.2, height: 2}),
// material definitions here ...
};
That is a huge improvement. I have replaced 27 lines of code with three that express my intent far better than before.I can see a similar improvement with a simple color material definition:
function colorMaterial(r, g, b) {
var Material = engine["gladius-cubicvr"].MaterialDefinition;
return new Material({color: [r, g, b]});
}
So that my entire resources hash, which had been nearly 45 lines of code, becomes: var resources = {
sphere_mesh: primitiveMesh('sphere'),
cone_mesh: primitiveMesh('cone', {height: 2, base: 2}),
cylinder_mesh: primitiveMesh('cylinder', {radius: 0.2, height: 2}),
red_material: colorMaterial(255, 0, 0),
blue_material: colorMaterial(0, 0, 255)
};
The last thing that I need to do is replace the onComplete
callback from the old engine.get()
call: // Mesh and material resources
var resources = {};
engine.get(
[
// Load meshes and materials ...
],
{
oncomplete: game.bind(null, engine, resources)
}
);
That game.bind()
call simply returns a function that, when invoked, will send engine
and resources
as the first two arguments to function game(engine, resources) {
// Game definition here...
}
In other words, onComplete()
would be the same thing as simply calling game(engine, resources)
, which is exactly what I do now: var resources = {
sphere_mesh: primitiveMesh('sphere'),
cone_mesh: primitiveMesh('cone', {height: 2, base: 2}),
cylinder_mesh: primitiveMesh('cylinder', {radius: 0.2, height: 2}),
red_material: colorMaterial(255, 0, 0),
blue_material: colorMaterial(0, 0, 255)
};
game(engine, resources);
That is a big win for clarity and, more importantly for a kids programming book, typing. This seems a good stopping point for tonight. Tomorrow I will get back to the topic of adding some wiggle to my avatar.Day #445
No comments:
Post a Comment