From 3a8d90a97cdd3eadd2c9054f46cfa71616235326 Mon Sep 17 00:00:00 2001 From: Svornost <11434-svornost@users.noreply.gitgud.io> Date: Mon, 8 Mar 2021 23:09:44 -0800 Subject: [PATCH] Use promises to stream textures directly from fetch and createImageBitmap instead of using the DOM and document event loop. --- src/art/webgl/engine.js | 56 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/art/webgl/engine.js b/src/art/webgl/engine.js index d15de10c69f..3eea5de383e 100644 --- a/src/art/webgl/engine.js +++ b/src/art/webgl/engine.js @@ -217,43 +217,47 @@ App.Art.Engine = class { } } - loadTexture(gl, url, engine) { - // return dummy texture + loadTexture(gl, url) { + // return dummy texture right now let texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255])); - // stream real textures - let image = new Image(); - image.onload = function() { - gl.bindTexture(gl.TEXTURE_2D, 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.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - - // hack to update canvas again after streaming is done - engine.loadCount += 1; - if (engine.loadCount == engine.sceneData.textures.length) { - let containers = document.getElementsByClassName("artContainer"); - for (let i = 0; i < containers.length; i++) { - containers[i].dispatchEvent(new Event("engineLoaded")); - } - } - }; - image.src = url; - - return texture; + // promise that real textures will stream in the future + let promise = fetch(url) + .then(response => response.blob()) + .then(blob => createImageBitmap(blob)) + .then(bitmap => { + gl.bindTexture(gl.TEXTURE_2D, 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.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); + + return texture; + }); + + return {texture, promise}; } initTextures() { // load model textures this.modelTextures = []; - this.loadCount = 0; + let promisedTextures = []; for (let i=0; i < this.sceneData.textures.length; i++) { - this.modelTextures[i] = this.loadTexture(this.gl, this.sceneData.textures[i], this); + const {texture, promise} = this.loadTexture(this.gl, this.sceneData.textures[i]); + this.modelTextures[i] = texture; + promisedTextures[i] = promise; } + Promise.all(promisedTextures).then(() => { + if (App.Art.engineReady) { // re-send loaded event after textures finish streaming + let containers = document.getElementsByClassName("artContainer"); + for (let i = 0; i < containers.length; i++) { + containers[i].dispatchEvent(new Event("engineLoaded")); + } + } + }); } initShaders() { -- GitLab