B/c file operations in JS are asynchronous we can’t control the order they’re finished loading.
Also we don’t control what arguments are passed to a callback b/c they’re pre-determined by the caller.
Otherwise you could easily pass the index to be used for each loaded file.
However JS had a hidden hack gem which can create a clone of a function w/ modified context this
and/or pre-filled parameters in addition to regular passed arguments:
Let’s take for example your loadObjectElement() function which invokes p5js loadModel() passing objectLoaded() as its callback:
'use strict';
const
ASSETS = 8,
TOTAL = ASSETS << 1, // 16
FOLDER = 'assets/',
OBJ_EXT = '.obj',
IMG_EXT = '.png',
objects = Array(ASSETS).fill(),
images = Array(ASSETS).fill();
var
loading = true,
objCounter = 0,
imgCounter = 0;
function setup() {
// blah, blah, blah...
for (var i = 0; i++ < ASSETS; ) {
loadObj(FOLDER + i + OBJ_EXT, i - 1);
loadImg(FOLDER + i + IMG_EXT, i - 1);
}
}
function draw() {
if (loading) return;
// blah, blah, blah...
}
function loadObj(filename, index) {
loadModel(filename, true, objectLoaded.bind(null, index));
}
function objectLoaded(idx, obj) {
objects[idx] = obj;
if (++objCounter + imgCounter == TOTAL) loading = false;
}
function loadImg(filename, index) {
loadImage(filename, imageLoaded.bind(null, index));
}
function imageLoaded(idx, img) {
images[idx] = img;
if (++imgCounter + objCounter == TOTAL) loading = false;
}
By passing a bind() callback to a loading function, we can force any number of preceding parameters to be filled w/ pre-determined arguments in addition to the caller’s sent arguments.
We already know the loading caller sends 1 argument to its callback, which is the loaded asset itself.
That’s why your objectLoaded() callback has 1 parameter named object:
In my “hacked” version I’ve added 1 extra parameter which comes before the regular parameter:
function objectLoaded(idx, obj) {
objects[idx] = obj;
if (++objCounter + imgCounter == TOTAL) loading = false;
}
That extra parameter is gonna be filled w/ the index value I’ve passed to bind():
function loadObj(filename, index) {
loadModel(filename, true, objectLoaded.bind(null, index));
}
And that’s the hacked trick!
BtW, the code gets smaller & less complex if you instead just use preload() to load your assets:
'use strict';
const
ASSETS = 8,
FOLDER = 'assets/',
OBJ_EXT = '.obj',
IMG_EXT = '.png',
objects = Array(ASSETS).fill(),
images = Array(ASSETS).fill();
function preload() {
for (var i = 0; i++ < ASSETS; ) {
loadObj(FOLDER + i + OBJ_EXT, i - 1);
loadImg(FOLDER + i + IMG_EXT, i - 1);
}
}
function loadObj(filename, index) {
loadModel(filename, true, objectLoaded.bind(null, index));
}
function objectLoaded(idx, obj) {
objects[idx] = obj;
}
function loadImg(filename, index) {
loadImage(filename, imageLoaded.bind(null, index));
}
function imageLoaded(idx, img) {
images[idx] = img;
}