Search code examples
webgljavascripttexture2d

raw jpeg data loading in webgl texture synchronously


Hi I hava jpeg compressed data stored in Uin8Array . I read about texture in Webgl . All Link what i saw initialize texture after loading image ( created by jpeg data , image.src = "some data" image.onload ( load texture ) ) . But this is asynchronus process . This process works fine . But can i use function compressedTexImage2D(target, level, internalFormat, width, height, border, data) internel format should be related to jpeg and data will be in form of compressed jpeg format ( width or height is not in form of pow of 2 ) so that whole process should be synchronous ? Or any other method in webgl that take jpeg compressed data directly without loading an image ?


Solution

  • So here is the bad news currently as of September 2012 WebGL does not actually support compressedTexImage2D. If you try calling the function it will always return an INVALID_ENUM error. If you are curious here is the section of the specification that explains it.

    Now the some what good news is that you can create a texture from a Uint8Array of jpeg data. I'm not sure how to do this synchronously, but maybe this code will help anyways.

    Basically we have to convert the original Uint8Array data into a base64 string, so we can create a new image with the base64 string as the image source.

    So here is the code:

    function createTexture(gl, data) {
        var stringData = String.fromCharCode.apply(null, new Uint16Array(data));
        var encodedData = window.btoa(stringData);
        var dataURI = "data:image/jpeg;base64," + encodedData;
    
        texture = gl.createTexture();
        texture.image = new Image();
    
        texture.image.onload = function () {
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            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.bindTexture(gl.TEXTURE_2D, null);
        };
    
        texture.image.src = dataURI;
    
        return texture;
    }
    

    I have a demo of the function here. To keep the file small I'm only using a 24x24 pixel jpeg. Just in case you are wondering, the function also works for jpeg's with non power of 2 heights/widths.

    If you want to see the full source code of the demo look here.