Hi,
im trying to load multiple OBJs and Images with callbacks into my sketch. The loading works fine but the Problem is that the Images and OBJs order is diffrent evreytime i load the sketch. So the images i take for the texture dont fit with the OBJs.
Heres my code and thx 4 ur help:)
let x = 1;
var objects = [];
var images = [];
var totalObjects = 8;
var totalImages = 8;
var counterObject = 0;
var counterImage = 0;
var loadingObject = false;
var loadingImage = false;
var loading = true;
function loadObjectElement(filename) {
loadModel(filename, true, objectLoaded);
function objectLoaded(object) {
console.log(filename);
append(objects, object);
counterObject++;
if (counterObject == totalObjects) {
loadingObject = true;
}
}
}
function loadImageElement(filename) {
loadImage(filename, imageLoaded);
function imageLoaded(image) {
console.log(filename);
append(images, image);
counterImage++;
if (counterImage == totalImages) {
loadingImage = true;
}
}
}
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
for (let i = 1; i <= 8; i++) {
loadObjectElement(“assets/” + i + “.obj”);
}
for (let i = 1; i <= 8; i++) {
loadImageElement(“assets/” + i + “.png”);
}
}
function draw() {
if ((loadingImage) && (loadingObject)) {
loading = false;
}
if (!loading) {
texture(images[x])
scale(3);
model(objects[x]);
}
}
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;
}