user8826104
user8826104

Reputation:

WebGL - Is it possible to pass gl into an img.onload function?

In my WebGL program that I'm writing in ES6, I have a class called Texture.

At first, it draws the texture as 1 red pixel. Once the image loads, I want to replace the red pixel with an image.

I'm a bit stuck as I'm not sure what the best approach for this as it currently throws an error and doesn't work:

Uncaught TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': No function was found that matched the signature provided.

My best guess is that this happens because JavaScript is asynchronous, so once the image loads, gl is gone, or maybe I'm wrong about this.

Help understanding this and/or a solution would be great appreciated.

export default class Texture {
    constructor(gl, src) {
        // create texture then bind it
        this.texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, this.texture);

        // texture settings for the texture
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

        // create it as a red pixel first so it can be quickly drawn then replaced with the actual image
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));

        // active the texture
        gl.activeTexture(gl.TEXTURE0);

        // load the image
        this.img = new Image();
        this.img.src = src;

        // replace the red pixel with the texture once it is loaded
        this.img.onload = function() {
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.img);
        }
    }
}

I did try this:

this.img.onload = function(gl) {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.img);
}

But it throws this error:

Uncaught TypeError: t.texImage2D is not a function

Upvotes: 1

Views: 412

Answers (2)

Tomasz Bubała
Tomasz Bubała

Reputation: 2153

Keyword this inside your onload function is not the same this context you expect. One way is to use arrow function as in Sebastian Speitel's answer.

You can also save the reference into self variable, which is a common pattern:

var self = this;
this.img.onload = function() {
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, self.img);
}

Any function can access a variable from outer scope, that's why self is accessible inside this.img.onload.

Upvotes: 0

Sebastian Speitel
Sebastian Speitel

Reputation: 7346

You are creating a new scope inside the function. The easiest way to prevent it in ES6 is an arrow function:

this.img.onload = () => {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.img);
}

Upvotes: 1

Related Questions