import { PostProcess } from 'babylonjs/PostProcesses/postProcess' ; import { Texture } from 'babylonjs/Materials/Textures/texture' ; import { GlobalState } from './components/globalState' ; import { RenderTargetTexture } from 'babylonjs/Materials/Textures/renderTargetTexture' ; import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture' ; import { Nullable } from 'babylonjs/types' ; import "./lod" ; import "./lodCube" ; export interface TextureChannelsToDisplay { R : boolean ; G : boolean ; B : boolean ; A : boolean ; } export class TextureHelper { private static async _ProcessAsync ( texture , width , height , face , channels , lod , globalState , resolve , reject ) { var scene = texture . getScene ( ) ! ; var engine = scene . getEngine ( ) ; let lodPostProcess ; if ( ! texture . isCube ) { lodPostProcess = new PostProcess ( "lod" , "lod" , [ "lod" ] , null , 1.0 , null , Texture . NEAREST_NEAREST_MIPNEAREST , engine ) ; } else { const faceDefines = [ "#define POSITIVEX" , "#define NEGATIVEX" , "#define POSITIVEY" , "#define NEGATIVEY" , "#define POSITIVEZ" , "#define NEGATIVEZ" , ] ; lodPostProcess = new PostProcess ( "lodCube" , "lodCube" , [ "lod" ] , null , 1.0 , null , Texture . NEAREST_NEAREST_MIPNEAREST , engine , false , faceDefines [ face ] ) ; } if ( ! lodPostProcess . getEffect ( ) . isReady ( ) ) { lodPostProcess . dispose ( ) ; setTimeout ( ( ) => { this . _ProcessAsync ( texture , width , height , face , channels , lod , globalState , resolve , reject ) ; } , 250 ) ; return ; } if ( globalState ) { globalState . blockMutationUpdates = true ; } let rtt = new RenderTargetTexture ( "temp" , { width : width , height : height } , scene , false ) ; lodPostProcess . onApply = function ( effect ) { effect . setTexture ( "textureSampler" , texture ) ; effect . setFloat ( "lod" , lod ) ; } ; const internalTexture = texture . getInternalTexture ( ) ; if ( rtt . renderTarget && internalTexture ) { const samplingMode = internalTexture . samplingMode ; texture . updateSamplingMode ( Texture . NEAREST_NEAREST_MIPNEAREST ) ; scene . postProcessManager . directRender ( [ lodPostProcess ] , rtt . renderTarget , true ) ; texture . updateSamplingMode ( samplingMode ) ; var numberOfChannelsByLine = width * 4 ; var halfHeight = height / 2 ; const bufferView = await engine . readPixels ( 0 , 0 , width , height ) ; const data = new Uint8Array ( bufferView . buffer , 0 , bufferView . byteLength ) ; if ( ! channels . R || ! channels . G || ! channels . B || ! channels . A ) { for ( var i = 0 ; i < width * height * 4 ; i += 4 ) { if ( channels . A && ! channels . R && ! channels . G && ! channels . B ) { data [ i ] = data [ i + 3 ] ; data [ i + 1 ] = data [ i + 3 ] ; data [ i + 2 ] = data [ i + 3 ] ; data [ i + 3 ] = 255 ; continue ; } let r = data [ i ] , g = data [ i + 1 ] , b = data [ i + 2 ] , a = data [ i + 3 ] ; if ( ! channels . A ) { a = 255 ; } if ( ! channels . R ) { if ( channels . G && ! channels . B ) { r = g ; } else if ( channels . B && ! channels . G ) { r = b ; } else { r = 0 ; } } if ( ! channels . G ) { if ( channels . R && ! channels . B ) { g = r ; } else if ( channels . B && ! channels . R ) { g = b ; } else { g = 0 ; } } if ( ! channels . B ) { if ( channels . R && ! channels . G ) { b = r ; } else if ( channels . G && ! channels . R ) { b = g ; } else { b = 0 ; } } data [ i ] = r ; data [ i + 1 ] = g ; data [ i + 2 ] = b ; data [ i + 3 ] = a ; } } if ( ( texture as Texture ) . invertY || texture . isCube ) { for ( var i = 0 ; i < halfHeight ; i ++ ) { for ( var j = 0 ; j < numberOfChannelsByLine ; j ++ ) { var currentCell = j + i * numberOfChannelsByLine ; var targetLine = height - i - 1 ; var targetCell = j + targetLine * numberOfChannelsByLine ; var temp = data [ currentCell ] ; data [ currentCell ] = data [ targetCell ] ; data [ targetCell ] = temp ; } } } resolve ( data ) ; engine . unBindFramebuffer ( rtt . renderTarget ) ; } else { reject ( ) ; } rtt . dispose ( ) ; lodPostProcess . dispose ( ) ; if ( globalState ) { globalState . blockMutationUpdates = false ; } } public static GetTextureDataAsync ( texture , width , height , face , channels , globalState ? , lod = 0 ) { return new Promise ( ( resolve , reject ) => { if ( ! texture . isReady ( ) && texture . _texture ) { texture . _texture . onLoadedObservable . addOnce ( ( ) => { this . _ProcessAsync ( texture , width , height , face , channels , lod , globalState || null , resolve , reject ) ; } ) ; return ; } this . _ProcessAsync ( texture , width , height , face , channels , lod , globalState || null , resolve , reject ) ; } ) ; } }