User:Tamas Bates/NetProto/WebGL/Notes

From XPUB & Lens-Based wiki

Safe Texture Loading

Loading and creating a new texture can cause problems if it's possible the texture might get used before it's ready. First of all, the images used in a texture may be downloaded after your page is finished loading, leaving you with an uninitialized texture if you start to render too early. But because the recommended process of creating a texture is to do so in the image's OnLoad event, you can still be left with an incomplete texture (missing mipmaps, for example) even after all the resources have been downloaded.

To avoid the extra headache of tracking the state of all your textures, create a 1x1 solid-color texture as a placeholder, then replace it with the real texture once it's ready. This can be done safely without needing to block your render loop until everything has been downloaded, and will allow your scene to render even if there's an error retrieving the resources for one or more textures (e.g. if you're pulling texture resources from another domain, the browser may block them as a security risk).

    var texture;
    function initTextures() {
         // create a new texture
        texture = gl.createTexture();
         // bind to the new texture so it's affected by future texture calls
        gl.bindTexture(gl.TEXTURE_2D, texture);

         // create a 1x1 pixel texture. The Uint8Array contains the RGBA values for the texture
         // A nice idea might be to use an average color from your intended texture
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, 
                      new Uint8Array([255,255,255,255])); // white

         // release the texture
        gl.bindTexture(gl.TEXTURE_2D, null);

         // create a new Image to hold our texture data
        var img= new Image();
         // hook OnLoad to do the actual texture creation after the image is ready for use (this call is asynchronous and will happen "whenever")
        img.onload = function() { handleTextureLoaded(img, texture); }
         // retrieve the desired image
        img.src = "some/url.jpg";
    }
    
    function handleTextureLoaded(img, tex) {
         // bind to the target texture (must have already been created by gl.createTexture)
        gl.bindTexture(gl.TEXTURE_2D, tex);
         // create a new texture from the content of the image
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
         // set your filtering parameters. NOTE: if using mipmaps (as below), your image MUST have dimensions matching a power of 2! Use gl.NEAREST instead of gl.LINEAR* for non-mipmapped textures.
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
        gl.generateMipmap(gl.TEXTURE_2D); // must be called before using the texture

         // release the texture
        gl.bindTexture(gl.TEXTURE_2D, null);
    }