JS "for" function too fast to load images
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

Hi, I'm using "playcanvas" so the code might look a bit strange however it is JS and I think you will understand the problem.
Basically when I fire the function myLoad("imageName.jpg"); a remote texture is loaded onto the mesh (myMeshNumber).

My problem, when the 3d file is loaded I run an for function. This loads the initial images onto the different meshes. I think the for function loops too fast and only the last image is loaded. Is there a way to fix this?

Note: the code works apart from the for function and if possible I would like it to do so after the fix :) (I don't want the fix to break the code).

var self = this;
var image = new Image();
image.crossOrigin = "anonymous";

image.onload = function () {
    var texture = new pc.Texture(self.app.graphicsDevice);
    texture.setSource(image);
    var material = self.entity.model.material;
    material.diffuseMap = texture;
    var myMesh =  pc.app.root.findByName(myProduct).model.meshInstances[myMeshNumber];

    myMesh.material = material;
    material.update();
};

    myLoad = function(myImage){
    image.src = myURL + myFolder + myImageFolder + myImage;
};

for (var i = 0; i < myImagesOnLoadArray.length; i++){
        alert(i);
        myMeshNumber = i;
        myLoad(myImagesOnLoadArray[i]+".jpg");
    }

UPDATE (not sure if this will help). There are two objects to mesh

This code drapes the last object only

for (var i = 0; i < myImagesOnLoadArray.length; i++){
        (function(idx){
            //alert(idx);
            myMeshNumber = idx;
            myLoad(myImagesOnLoadArray[idx]+".jpg");
        }(i));
    }

This code drapes the first object only

for (var i = 0; i < myImagesOnLoadArray.length; i++){
        console.log("Load - " + myImagesOnLoadArray[i] + i);
        myLoad(myImagesOnLoadArray[i]+".jpg", i);
    }

UPDATE 2

If feel bad just writing this but I just gave up and hacked it in the end. Thanks for your help I know I did not give you much to work with.
I think the problem is that the first image needs to be loaded before the next image is fired.

    // Hack to get first images to load :(
    var yyy = 0;
    for (var i = 0; i < myImagesOnLoadArray.length; i++){
        var time = 3000*i;
        setTimeout(sample, time);
    }

    function sample(){
        myMeshNumber = yyy;
        myLoad(myImagesOnLoadArray[yyy]+".jpg");
        yyy++;
    }
I think, you need to paste some more code. We need to see where the myMeshNumber and myImagesOnLoadArray variables are being declared. And what exactly do you mean "when the 3d file is loaded"?
kostasx 5 months ago
awarded to quillford

Crowdsource coding tasks.

2 Solutions

Winning solution

the way myLoad() is currently implemented, it will only use the latest image it was passed because you only have one image variable that you keep changing the src for. the code below creates a new Image for each image and stores them in an array called images

I can't really test this but I think it'll work

var self = this;
var images = new Array();

myLoad = function(myImage, index){
    images[index] = new Image();
    images[index].crossOrigin = "anonymous";
    images[index].src = myURL + myFolder + myImageFolder + myImage;

    images[index].onload = function() {
        var texture = new pc.Texture(self.app.graphicsDevice);
        texture.setSource(images[index]);
        var material = self.entity.model.material;
        material.diffuseMap = texture;
        var myMesh =  pc.app.root.findByName(myProduct).model.meshInstances[index];

        myMesh.material = material;
        material.update();
    }
};

for (var i = 0; i < myImagesOnLoadArray.length; i++){
    alert(i);
    myMeshNumber = i;
    myLoad(myImagesOnLoadArray[i]+".jpg", i);
}
i'm not familiar enough with playcanvas to say, but we can test that if the new code doesn't work
quillford 5 months ago
Thanks quillford I will try to test it. One question, would we have to store the "myMeshNumber" var too? Thinking about it maybe this is what is creating the problem, the "myMeshNumber" is changing before the function is called...
Jacknumpty 5 months ago
I updated the solution to make sure it uses the right number when image onload function is called
quillford 5 months ago
I'm getting "index is not defined"
Jacknumpty 5 months ago
fixed
quillford 5 months ago
I'm getting a problem with this myLoad = function(myImage){ image.src = myURL + myFolder + myImageFolder + myImage; }; I changed it to this but it is still erroring myLoad = function(myImage, myMeshNumber){ images[0].src = myURL + myFolder + myImageFolder + myImage; };
Jacknumpty 5 months ago
I don't understand. did you try the code I posted unmodified?
quillford 5 months ago
Sorry... it's working but the same texture (image) is being added to both meshes.
Jacknumpty 5 months ago
the texture, material, and myMesh variables are reused and seem to only exist in the scope of the onload function. that seems like a problem to me, but again I'm not familiar with playcanvas
quillford 5 months ago
Yes, it's getting late here, let me have a look at it in the morning. Thank you for your help, your solution looks good to me.
Jacknumpty 5 months ago

I think this might be a closure issue with the for loop. Please try the next code which encapsulates the for loop callback in an IIFE:

    var self = this;
    var image = new Image();
    image.crossOrigin = "anonymous";

    image.onload = function () {
        var texture = new pc.Texture(self.app.graphicsDevice);
        texture.setSource(image);
        var material = self.entity.model.material;
        material.diffuseMap = texture;
        var myMesh =  pc.app.root.findByName(myProduct).model.meshInstances[myMeshNumber];

        myMesh.material = material;
        material.update();
    };

        myLoad = function(myImage){
        image.src = myURL + myFolder + myImageFolder + myImage;
    };

    for (var i = 0; i < myImagesOnLoadArray.length; i++){


        // Code Changed
        (function(idx){

            alert(idx);
            myMeshNumber = idx;
            myLoad(myImagesOnLoadArray[idx]+".jpg");

        }(i));

    }
Hi kostasx, thank you. I have updated my question.
Jacknumpty 5 months ago
I am not sure what you are trying to achieve here. See my comment on updating the code. Maybe you need to place the for loop inside the image.onload callback perhaps?
kostasx 5 months ago
View Timeline