import * as THREE from "three" ; import { ImageItem , TexturizableImage } from "./Image" ; const isNode = typeof window === "undefined" ; internal export class MipMapGenerator { param width param height static getPaddedSize ( width , height ) { return { width : THREE . MathUtils . ceilPowerOfTwo ( width ) , height : THREE . MathUtils . ceilPowerOfTwo ( height ) } ; } private readonly m_paddingCanvas ? : HTMLCanvasElement ; private readonly m_paddingContext ? : CanvasRenderingContext2D ; private readonly m_resizeCanvas ? : HTMLCanvasElement ; private readonly m_resizeContext ? : CanvasRenderingContext2D ; constructor ( ) { if ( ! isNode ) { this . m_paddingCanvas = document . createElement ( "canvas" ) ; this . m_paddingContext = this . m_paddingCanvas . getContext ( "2d" ) ! ; this . m_resizeCanvas = document . createElement ( "canvas" ) ; this . m_resizeContext = this . m_resizeCanvas . getContext ( "2d" ) ! ; } } param image returns generateTextureAtlasMipMap ( image ) { if ( isNode ) { throw new Error ( "MipMapGenerator only works in browser." ) ; } if ( image . image === undefined ) { throw new Error ( "Can not generate mip maps. Image data not loaded!" ) ; } const imageData = image . image ; const mipMaps = [ ] ; const { width : paddedWidth , height : paddedHeight } = MipMapGenerator . getPaddedSize ( imageData . width , imageData . height ) ; this . copyImageWithPadding ( imageData , paddedWidth , paddedHeight ) ; mipMaps . push ( this . m_paddingContext ! . getImageData ( 0 , 0 , paddedWidth , paddedHeight ) ) ; let width = paddedWidth * 0.5 ; let height = paddedHeight * 0.5 ; while ( width >= 1 || height >= 1 ) { const mipMapLevel = mipMaps . length ; const previousImage = mipMaps [ mipMapLevel - 1 ] ; mipMaps . push ( this . resizeImage ( previousImage , Math . max ( width , 1 ) , Math . max ( height , 1 ) ) ) ; width *= 0.5 ; height *= 0.5 ; } return mipMaps ; } param image param width param height returns private copyImageWithPadding ( image , width , height ) { this . m_paddingCanvas ! . width = width ; this . m_paddingCanvas ! . height = height ; this . m_paddingContext ! . clearRect ( 0 , 0 , width , height ) ; if ( image instanceof ImageData ) { this . m_paddingContext ! . putImageData ( image , 0 , 0 ) ; } else { this . m_paddingContext ! . drawImage ( image , 0 , 0 ) ; } if ( image . width !== width ) { this . m_paddingContext ! . drawImage ( this . m_paddingCanvas ! , image . width - 1 , 0 , 1 , image . height , image . width , 0 , width - image . width , image . height ) ; } if ( image . height !== height ) { this . m_paddingContext ! . drawImage ( this . m_paddingCanvas ! , 0 , image . height - 1 , width , 1 , 0 , image . height , width , height - image . height ) ; } return this . m_paddingCanvas ! ; } param image param width param height return private resizeImage ( image , width , height ) { const paddedImage = this . copyImageWithPadding ( image , image . width , image . height ) ; this . m_resizeCanvas ! . width = width ; this . m_resizeCanvas ! . height = height ; this . m_resizeContext ! . clearRect ( 0 , 0 , width , height ) ; this . m_resizeContext ! . drawImage ( paddedImage , 0 , 0 , width , height ) ; return this . m_resizeContext ! . getImageData ( 0 , 0 , width , height ) ; } }