import { NodeRenderContext } from "@/lib/designer" ; import { TextureDataType } from "@/lib/designer/gl" ; import { FloatProperty } from "@/lib/designer/properties" ; import { TextureDataConverter } from "@/lib/designer/texturedataconverter" ; import { DesignerNode } from "../../designer/designernode" ; export class Bevel extends DesignerNode { f : Float64Array ; z : Float64Array ; v : Uint16Array ; grid : Float64Array ; gridInner : Float64Array ; gridOuter : Float64Array ; resultPixels : Float32Array ; readPixels : Float32Array ; readFbo : WebGLFramebuffer ; distanceProp : FloatProperty ; width : number ; height : number ; converter : TextureDataConverter ; public init ( ) { this . title = "Bevel" ; this . addInput ( "image" ) ; this . distanceProp = this . addFloatProperty ( "distance" , "Distance" , 50.0 , 0.0 , 100.0 , 0.01 ) ; this . initArrays ( ) ; this . readFbo = this . gl . createFramebuffer ( ) ; this . converter = new TextureDataConverter ( this . gl as WebGL2RenderingContext ) ; } private initArrays ( ) { const width = this . designer . width ; const height = this . designer . height ; this . width = width ; this . height = height ; let size = Math . max ( width , height ) ; this . f = new Float64Array ( size * 3 ) ; this . z = new Float64Array ( size * 3 + 1 ) ; this . v = new Uint16Array ( size * 3 ) ; let gridSize = width * height ; this . grid = new Float64Array ( gridSize ) ; this . gridOuter = new Float64Array ( gridSize ) ; this . gridInner = new Float64Array ( gridSize ) ; this . resultPixels = new Float32Array ( width * height * 4 ) ; this . readPixels = new Float32Array ( width * height * 4 ) ; } public render ( context ) { const inputs = context . inputs ; if ( inputs . length == 0 ) return ; let inputTexture = inputs [ 0 ] . node . tex ; if ( this . designer . width != this . width || this . designer . height != this . height ) { this . initArrays ( ) ; } const width = this . designer . width ; const height = this . designer . height ; const gridOuter = this . gridOuter ; const gridInner = this . gridInner ; const grid = this . grid ; let gridSize = width * height ; let gl = context . gl as WebGL2RenderingContext ; this . readPixels = new Float32Array ( this . converter . getData ( inputTexture , width , height , TextureDataType . Float32 ) ) ; const VALUE_MAX = 15360.0 ; let pixels = this . readPixels ; for ( let i = 0 ; i < gridSize ; i ++ ) { let a = pixels [ i * 4 + 0 ] ; this . gridOuter [ i ] = a === 1 ? 0 : a === 0 ? INF : Math . pow ( Math . max ( 0 , 0.5 - a ) , 2 ) ; this . gridInner [ i ] = a === 1 ? INF : a === 0 ? 0 : Math . pow ( Math . max ( 0 , a - 0.5 ) , 2 ) ; } edt ( this . gridOuter , width , height , this . f , this . v , this . z ) ; edt ( this . gridInner , width , height , this . f , this . v , this . z ) ; let min = 1.0 ; let max = 0 ; let radius = this . distanceProp . getValue ( ) ; let offset = 0.25 ; for ( let i = 0 ; i < gridSize ; i ++ ) { let d = Math . sqrt ( gridOuter [ i ] ) - Math . sqrt ( gridInner [ i ] ) ; var col = VALUE_MAX - VALUE_MAX * ( d / radius + offset ) ; col = Math . max ( 0 , Math . min ( VALUE_MAX , col ) ) ; min = Math . min ( min , col ) ; max = Math . max ( max , col ) ; grid [ i ] = col ; } let range = max - min ; let scale = 1.0 / range ; let resultPixels = this . resultPixels ; for ( let i = 0 ; i < gridSize ; i ++ ) { let col = 1.0 - ( grid [ i ] - min ) * scale ; resultPixels [ i * 4 + 0 ] = col ; resultPixels [ i * 4 + 1 ] = col ; resultPixels [ i * 4 + 2 ] = col ; resultPixels [ i * 4 + 3 ] = 1.0 ; } gl . bindTexture ( gl . TEXTURE_2D , this . tex ) ; const level = 0 ; const internalFormat = gl . RGBA16F ; const border = 0 ; const format = gl . RGBA ; const type = gl . FLOAT ; const data = resultPixels ; gl . texImage2D ( gl . TEXTURE_2D , level , internalFormat , this . designer . width , this . designer . height , border , format , type , data ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . LINEAR ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . LINEAR ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . REPEAT ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . REPEAT ) ; gl . bindTexture ( gl . TEXTURE_2D , null ) ; } } var INF = 1e20 ; function edt ( data , width , height , f , v , z ) { for ( let x = 0 ; x < width ; x ++ ) edt1d ( data , x , width , height , f , v , z ) ; for ( let y = 0 ; y < height ; y ++ ) edt1d ( data , y * width , 1 , width , f , v , z ) ; } function edt1d ( grid , offset , stride , length , f , v , z ) { let q , k , s , r ; v [ 0 ] = 0 ; z [ 0 ] = - INF ; z [ 1 ] = INF ; for ( q = 0 ; q < length ; q ++ ) f [ q ] = grid [ offset + q * stride ] ; for ( q = 0 ; q < length ; q ++ ) f [ q + length ] = grid [ offset + q * stride ] ; for ( q = 0 ; q < length ; q ++ ) f [ q + length + length ] = grid [ offset + q * stride ] ; for ( q = 1 , k = 0 , s = 0 ; q < length * 3 ; q ++ ) { do { r = v [ k ] ; s = ( f [ q ] - f [ r ] + q * q - r * r ) / ( q - r ) / 2 ; } while ( s <= z [ k ] && -- k > - 1 ) ; k ++ ; v [ k ] = q ; z [ k ] = s ; z [ k + 1 ] = INF ; } for ( q = length , k = 0 ; q < length + length ; q ++ ) { while ( z [ k + 1 ] < q ) k ++ ; r = v [ k ] ; grid [ offset + ( q - length ) * stride ] = f [ r ] + ( q - r ) * ( q - r ) ; } }