I want to upload a texture to webgl, and most tutorials do something like this:
var textureImage = new Image();
textureImage.src = "img/texture.png";
textureImage.onload = function() { ...texture loading code... };
So the texture doesn't actually get uploaded to webgl until later, after the image has loaded.
However, I have an image on the DOM that I want to use as a texture, and this image will for sure be loaded because my JavaScript doesn't run until all of the page's content has fully loaded.
How do I get that image on the DOM and upload it to webgl immediately? Instead of waiting for a callback.
It's not because your page has fully loaded that your images are loaded too. They are not necessary on your page.
Even if that is the case, you can use onload callback without problem: it will be called as soon as you start the image loading if it is already loaded.
If your try to bind a texture that is not fully loaded, your surface will use instead a complete white texture (or black, in some cases). So you should see the difference yourself.
By the way: to prevent a load before your callback set, it is preferable to set your callback function before your source:
var textureImage = new Image();
textureImage.onload = function() { ...texture loading code... }; // First the callback...
textureImage.src = "img/texture.png"; // Then the source.
Related
With Phaser I am working on a game. This game rewards the player with an item that is not capable of being preloaded. After an Ajax call I was hoping to load the image and then display it in the phaser animation. Is there anyway to do this?
Flow: Game is playing
Game Completes and Ajax Call is made.
Ajax responds with which image to use.
Phaser loads image and displays what they won.
You can use Phaser's loader to load an image at anytime by invoking
game.load.image('referenceName', 'assets/pics/file.jpg');
then you can set an event like the ones at
http://phaser.io/examples/v2/loader/load-events
game.load.onLoadComplete.add(aFunctionToCall, this);
But most importantly don't forget to actually tell the loader to start after you've set everything up.
game.load.start();
Lazzy loading in Phaser 3 can be done by using the Phaser.Loader.LoaderPlugin(scene)
lazzyLoading:function(){
var name = 'card-back';
// texture needs to be loaded to create a placeholder card
const card = this.add.image(WIDTH/2, HEIGHT/2, name);
let loader = new Phaser.Loader.LoaderPlugin(this);
// ask the LoaderPlugin to load the texture
loader.image(name, 'assets/images/demon-large1.png');
loader.once(Phaser.Loader.Events.COMPLETE, () => {
// texture loaded so use instead of the placeholder
card.setTexture(name)
});
loader.start();
}
I have a canvas with some pictures and I would like to load it onto a texture much like an image with ImageUtils. As you know canvas has no 'onfinished' rendering callback so I am at the mercy of THREE here. I have come across this but this seems to be tightly coupled with AJAX.
You can read the image from the canvas as a data url:
var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
After you execute drawImage on the canvas, the image data is already going to be inside there.
These data urls then can be used as textures in Three.js.
var texture = THREE.ImageUtils.loadTexture(dataURL);
Update
You could also try this for debugging:
var texture = THREE.ImageUtils.loadTexture(dataURL, undefined, function(texture){
// Handler for onLoad, this returns the img
console.log(texture);
},
function(event){
// Handler for onError, it returns the error event
console.log(event);
});
Now my entire project is too big for a copy and paste, but here is a basic breakdown of what I'm doing right now:
$(document).ready(function(){
var canvas = $('#Canvas');
var data = {source: "images\pattern.png", repeat: "repeat"} ;
var pattern = canvas.createPattern(data); //Returns 'Null' at random
});
Things I've looked at so far:
Loading time (Somewhat related, it seems to break more often when the page loads faster)
Loading order (Doesn't seem related)
Preloading the image by forcing it to an on-page image beforehand (Doesn't fix it )
Preloading it using Image() and passing the image path to Image().src (doesn't fix it either)
Passing the Image() as data.source instead of a string path (might have helped just a little)
Initting JCanvas beforehand (No function seems to exists for this)
Creating the pattern as early or as late as possible (Seems to change the frequency, but not by a lot)
It seems to have a mind of it's own and I can't figure out what I'm doing wrong. Anyone have a clue as to what I'm doing wrong?
-Edit1-
Debugging through the Jcanvas source right now and I think it has something to do with the context. Is there any way for me to preload the canvas context?
-Edit2-
Forget everything I've said about the context, I think I figured it out.
//JCanvas source
[...]
else {
// Use URL if given to get the image
img = new Image();
img.crossOrigin = params.crossOrigin;
img.src = source; //<-- source is the url of my image ("images\pattern.png")
}
// Create pattern if already loaded
if (img.complete || imgCtx) {
onload(); //<-- When this runs, the image pops up perfectly fine
} else {
img.onload = onload(); //<-- This is what causes the problem,
//onload never seems to actually run
// Fix onload() bug in IE9
img.src = img.src;
}
The img.onload event should happen directly after an image loads, but it never seems to happen.
So far my program is working the way I want it to. This works fine:
// Player object
var player = {
x: 10,
y: 10,
draw: function () {
ctx.drawImage(playerImg, 0, 0);
...
Should I check if playerImg is loaded first, even though it works correctly so far?
Also, what is the best way to check. I was thinking about putting all the images in an array. Then check with the onLoad function. If they are all loaded then I will start the game loop. Is this a good idea?
Thanks
How image loading works
You need to check if the image is loaded as image loading is asynchronous. You may experience that your code works sometimes without. This is mainly because your image exists in the cache and the browser is able to load it fast enough before the drawImage is called, or the image exists on local disk.
However, new users will need to download the data first and you don't want first-time users to experience errors such as images not showing because they are not finished loading.
As it works asynchronous your code will continue to execute while the image loading takes place in the background. This may cause your code to execute before the image has finished loading. So handling image loading is important
Handling multiple images
You can load all your images first (or those you need to start with) and you can define them using array:
var imageURLs = [url1, url2, url3, ...],
images = [],
count = imageURLs.length;
Then iterate and create the image elements:
for(var i = 0; i < count; i++) {
/// create a new image element
var img = new Image();
/// element is valid so we can push that to stack
images.push(img);
/// set handler and url
img.onload = onloadHandler;
img.src = imageURLs[i];
/// if image is cached IE (surprise!) may not trigger onload
if (img.complete) onloadHandler().bind(img);
}
and in the callback function do the inventory count:
function onloadHandler() {
/// optionally: "this" contains current image just loaded
count--;
if (count === 0) callbackDone();
}
Your callback is the code you want to execute next. Your images will be in the array images in the same order as the imageURLs.
For production you should also incorporate an onerror handler in case something goes wrong.
I am coding a script in which the user selects a range of data, and then I fetch a bunch of images (over 150) from the server and then I loop trough them to make something like a movie. What I want to know is the most efficient way to load prevent lag when moving trough the images.
Currently I am fetching the images from the server using Ajax and store them in a array of Image objects on the JavaScript. In the HTML I have a div tag in which I wish to put the images. After I finished creating all the Image object (and setting their proper src) in the array, I do the following:
imgElem = document.createElement('img');
document.getElementById('loopLocation').appendChild(imgElem);
imgElem.src = images[0].src;
After this I just make that last call but changing the loop index. I do that every 400ms. The loop works, but sometimes it lags and it freezes on an image for longer that it is supposed to be. I want to know if I am able to improve this anymore from the client side or I just need a server that responds faster.
you might wanna consider spriting which is putting all images into one big image. with this, you only need to load one big image, and then just reposition for every scene.
or, you might also want to pre-load those 150 images, before actually using them. you can use JS array to store Image objects and then loop through that array to get your images.
var images = [];
var expectLoaded = 150;
for(var i = 0; i<expectLoaded;i++){
(function(i){
//new image object
var img = new Image();
//onload hander
img.onload = function(){
//after load, push it into the array
images.push[img];
//and check if the all has loaded
if(images.length === expectLoaded){
//preload done
}
}
//start loading this image
img.src = //path to image[i];
},(i));
}
loops block the UI thread. JS is single-threaded, meaning code gets executed in a linear fashion, one after the other. anything that comes after that loop statement will wait until the loop finishes. if that loop takes long... grab some coffee. plus, since you are manipulating the DOM, you don't see the changes since the UI thread is blocked.
but there are ways to bypass this, and one of them is using timeouts to delay and queue the code for later execution, when JS is not busy.
function animate(frameNo){
//animate frame[frameNo];
if(frameNo < total_frames){ //make the UI breate in between frames
setTimeout(function(){ //so that changes reflect on the screen
animate(++frameNo); //then animate next frame
},200);
}
}
//start
animate(0);
I agree with Joseph on his second point. Here's a nice link to accomplish image preloading before you start the loop: http://www.javascriptkit.com/javatutors/preloadimagesplus.shtml