2025-01-22 16:18:30 +01:00
package leenkx . renderpath ;
import iron . RenderPath ;
import iron . object . LightObject ;
import leenkx . math . Helper ;
import kha . arrays . Float32Array ;
class Inc {
2025-05-28 01:36:04 +00:00
static var path: RenderPath ;
public static var superSample = 1.0 ;
static var pointIndex = 0 ;
static var spotIndex = 0 ;
static var lastFrame = - 1 ;
#if ( ( rp_voxels != ' O f f ' ) && lnx_config )
static var voxelsCreated = false ;
#end
#if ( rp_voxels != " O f f " )
static var voxel_sh0: kha . compute . Shader = null ;
static var voxel_sh1: kha . compute . Shader = null ;
static var voxel_ta0: kha . compute . TextureUnit ;
static var voxel_tb0: kha . compute . TextureUnit ;
static var voxel_ca0: kha . compute . ConstantLocation ;
static var voxel_cb0: kha . compute . ConstantLocation ;
static var voxel_ta1: kha . compute . TextureUnit ;
static var voxel_tb1: kha . compute . TextureUnit ;
static var voxel_tc1: kha . compute . TextureUnit ;
static var m = iron . math . Mat4 . identity ( ) ;
static var voxel_ca1: kha . compute . ConstantLocation ;
static var voxel_cb1: kha . compute . ConstantLocation ;
#if ( rp_voxels == " V o x e l G I " )
static var voxel_td1: kha . compute . TextureUnit ;
static var voxel_te1: kha . compute . TextureUnit ;
static var voxel_cc1: kha . compute . ConstantLocation ;
#else
#if lnx_voxelgi_shadows
static var voxel_te1: kha . compute . TextureUnit ;
#end
#end
#if ( lnx_voxelgi_shadows || rp_voxels == " V o x e l G I " )
static var voxel_sh2: kha . compute . Shader = null ;
static var voxel_ta2: kha . compute . TextureUnit ;
static var voxel_tb2: kha . compute . TextureUnit ;
static var voxel_ca2: kha . compute . ConstantLocation ;
static var voxel_cb2: kha . compute . ConstantLocation ;
static var voxel_cc2: kha . compute . ConstantLocation ;
#end
static var voxel_sh3: kha . compute . Shader = null ;
static var voxel_ta3: kha . compute . TextureUnit ;
static var voxel_tb3: kha . compute . TextureUnit ;
static var voxel_tc3: kha . compute . TextureUnit ;
static var voxel_td3: kha . compute . TextureUnit ;
static var voxel_te3: kha . compute . TextureUnit ;
static var voxel_tf3: kha . compute . TextureUnit ;
#if lnx_brdf
static var voxel_tg3: kha . compute . TextureUnit ;
#end
#if lnx_radiance
static var voxel_th3: kha . compute . TextureUnit ;
#end
static var voxel_ca3: kha . compute . ConstantLocation ;
static var voxel_cb3: kha . compute . ConstantLocation ;
static var voxel_cc3: kha . compute . ConstantLocation ;
static var voxel_cd3: kha . compute . ConstantLocation ;
static var voxel_ce3: kha . compute . ConstantLocation ;
#if lnx_irradiance
static var voxel_cf3: kha . compute . ConstantLocation ;
#end
#if lnx_radiance
static var voxel_cg3: kha . compute . ConstantLocation ;
#end
#if lnx_envcol
static var voxel_ch3: kha . compute . ConstantLocation ;
#end
#if ( rp_voxels == " V o x e l G I " )
static var voxel_sh4: kha . compute . Shader = null ;
static var voxel_ta4: kha . compute . TextureUnit ;
static var voxel_tb4: kha . compute . TextureUnit ;
static var voxel_tc4: kha . compute . TextureUnit ;
static var voxel_td4: kha . compute . TextureUnit ;
static var voxel_te4: kha . compute . TextureUnit ;
static var voxel_tf4: kha . compute . TextureUnit ;
static var voxel_ca4: kha . compute . ConstantLocation ;
static var voxel_cb4: kha . compute . ConstantLocation ;
static var voxel_cc4: kha . compute . ConstantLocation ;
static var voxel_cd4: kha . compute . ConstantLocation ;
#end
#end //rp_voxels
public static function init ( _path : RenderPath ) {
path = _path ;
#if lnx_config
var config = leenkx . data . Config . raw ;
for ( l in iron . Scene . active . lights ) {
l . data . raw . shadowmap_size = l . data . raw . type == " s u n " ?
config . rp_shadowmap_cascade :
config . rp_shadowmap_cube ;
}
superSample = config . rp_supersample ;
#else
#if ( rp_supersampling == 1.5 )
superSample = 1.5 ;
#elseif ( rp_supersampling == 2 )
superSample = 2.0 ;
#elseif ( rp_supersampling == 4 )
superSample = 4.0 ;
#end
#end
}
#if lnx_shadowmap_atlas
public static function updatePointLightAtlasData ( transparent : Bool ) : Void {
var atlas = transparent ? ShadowMapAtlas . shadowMapAtlasesTransparent . get ( ShadowMapAtlas . shadowMapAtlasName ( " p o i n t " , true ) ) : ShadowMapAtlas . shadowMapAtlases . get ( ShadowMapAtlas . shadowMapAtlasName ( " p o i n t " , false ) ) ;
if ( atlas != null ) {
if ( LightObject . pointLightsData == null ) {
LightObject . pointLightsData = new kha . arrays . Float32Array (
LightObject . maxLightsCluster * ShadowMapTile . tilesLightType ( " p o i n t " ) * 4 ) ; // max possible visible lights * 6 or 2 (faces) * 4 (xyzw)
}
var n = iron . Scene . active . lights . length > LightObject . maxLightsCluster ? LightObject . maxLightsCluster : iron . Scene . active . lights . length ;
var i = 0 ;
var j = 0 ;
for ( light in iron . Scene . active . lights ) {
if ( i >= n )
break ;
if ( LightObject . discardLightCulled ( light ) ) continue ;
if ( light . data . raw . type == " p o i n t " ) {
if ( ! light . data . raw . cast_shadow ) {
j += 4 * 6 ;
continue ;
}
for ( k in 0 ... 6 ) {
LightObject . pointLightsData [ j ] = light . tileOffsetX [ k ] ; // posx
LightObject . pointLightsData [ j + 1 ] = light . tileOffsetY [ k ] ; // posy
LightObject . pointLightsData [ j + 2 ] = light . tileScale [ k ] ; // tile scale factor relative to atlas
LightObject . pointLightsData [ j + 3 ] = 0 ; // padding
j += 4 ;
}
}
i ++ ;
}
}
}
public static function bindShadowMapAtlas ( ) {
for ( atlas in ShadowMapAtlas . shadowMapAtlases ) {
path . bindTarget ( atlas . target , atlas . target ) ;
}
#if rp_shadowmap_transparent
for ( atlas in ShadowMapAtlas . shadowMapAtlasesTransparent ) {
path . bindTarget ( atlas . target , atlas . target ) ;
}
#end
}
static function getShadowMapAtlas ( atlas : ShadowMapAtlas , transparent : Bool ) : String {
inline function createDepthTarget ( name : String , size : Int ) {
var t = new RenderTargetRaw ( ) ;
t . name = name ;
t . width = t . height = size ;
t . format = transparent ? " R G B A 6 4 " : " D E P T H 1 6 " ;
return path . createRenderTarget ( t ) ;
}
var rt = path . renderTargets . get ( atlas . target ) ;
// Create shadowmap atlas texture on the fly and replace existing on size change
if ( rt == null ) {
rt = createDepthTarget ( atlas . target , atlas . sizew ) ;
}
e lse if ( atlas . updateRenderTarget ) {
atlas . updateRenderTarget = false ;
// Resize shadow map
rt . unload ( ) ;
rt = createDepthTarget ( atlas . target , atlas . sizew ) ;
}
return atlas . target ;
}
public static function drawShadowMapAtlas ( ) {
#if rp_shadowmap
#if rp_probes
// Share shadow map with probe
if ( lastFrame == RenderPath . active . frame )
return ;
lastFrame = RenderPath . active . frame ;
#end
#if lnx_debug
beginShadowsLogicProfile ( ) ;
// reset data on rejected lights
for ( atlas in ShadowMapAtlas . shadowMapAtlases ) {
atlas . rejectedLights = [ ] ;
}
#if rp_shadowmap_transparent
for ( atlas in ShadowMapAtlas . shadowMapAtlasesTransparent ) {
atlas . rejectedLights = [ ] ;
}
#end
#end
for ( light in iron . Scene . active . lights ) {
if ( ! light . lightInAtlas && ! light . culledLight && light . visible && light . shadowMapScale > 0.0
& & light . data . raw . strength > 0.0 && light . data . raw . cast_shadow ) {
ShadowMapAtlas . addLight ( light , false ) ;
}
#if rp_shadowmap_transparent
if ( ! light . lightInAtlasTransparent && ! light . culledLight && light . visible && light . shadowMapScale > 0.0
& & light . data . raw . strength > 0.0 && light . data . raw . cast_shadow ) {
ShadowMapAtlas . addLight ( light , true ) ;
}
#end
}
// update point light data before rendering
updatePointLightAtlasData ( false ) ;
#if rp_shadowmap_transparent
updatePointLightAtlasData ( true ) ;
#end
for ( atlas in ShadowMapAtlas . shadowMapAtlases ) {
var tilesToRemove = [ ] ;
#if lnx_shadowmap_atlas_lod
var tilesToChangeSize = [ ] ;
#end
var shadowmap = getShadowMapAtlas ( atlas , false ) ;
path . setTargetStream ( shadowmap ) ;
path . clearTarget ( null , 1.0 ) ;
for ( tile in atlas . activeTiles ) {
if ( tile . light == null || ! tile . light . visible || tile . light . culledLight
| | ! tile . light . data . raw . cast_shadow || tile . light . data . raw . strength == 0 ) {
tile . unlockLight = true ;
tilesToRemove . push ( tile ) ;
continue ;
}
#if lnx_shadowmap_atlas_lod
var newTileSize = atlas . getTileSize ( tile . light . shadowMapScale ) ;
if ( newTileSize != tile . size ) {
if ( newTileSize == 0 ) {
tile . unlockLight = true ;
tilesToRemove . push ( tile ) ;
continue ;
}
// queue for size change
tile . newTileSize = newTileSize ;
tilesToChangeSize . push ( tile ) ;
}
#end
// set the tile offset for this tile and every linked tile to this one
var j = 0 ;
tile . forEachTileLinked ( function ( lTile ) {
tile . light . tileOffsetX [ j ] = lTile . coordsX / atlas . sizew ;
tile . light . tileOffsetY [ j ] = lTile . coordsY / atlas . sizew ;
tile . light . tileScale [ j ] = lTile . size / atlas . sizew ;
j ++ ;
} ) ;
// set shadowmap size for uniform
tile . light . data . raw . shadowmap_size = atlas . sizew ;
path . light = tile . light ;
var face = 0 ;
var faces = ShadowMapTile . tilesLightType ( tile . light . data . raw . type ) ;
#if lnx_debug
beginShadowsRenderProfile ( ) ;
#end
tile . forEachTileLinked ( function ( lTile ) {
if ( faces > 1 ) {
#if lnx_csm
switch ( tile . light . data . raw . type ) {
c ase " s u n " : tile . light . setCascade ( iron . Scene . active . camera , face ) ;
c ase " p o i n t " : path . currentFace = face ;
}
#else
path . currentFace = face ;
#end
face ++ ;
}
path . setCurrentViewportWithOffset ( lTile . size , lTile . size , lTile . coordsX , lTile . coordsY ) ;
path . drawMeshesStream ( " s h a d o w m a p " ) ;
} ) ;
#if lnx_debug
endShadowsRenderProfile ( ) ;
#end
path . currentFace = - 1 ;
}
path . endStream ( ) ;
}
#if rp_shadowmap_transparent
for ( atlas in ShadowMapAtlas . shadowMapAtlasesTransparent ) {
var tilesToRemove = [ ] ;
#if lnx_shadowmap_atlas_lod
var tilesToChangeSize = [ ] ;
#end
var shadowmap = getShadowMapAtlas ( atlas , true ) ;
path . setTargetStream ( shadowmap ) ;
path . clearTarget ( 0xffffff , 0.0 ) ;
for ( tile in atlas . activeTiles ) {
if ( tile . light == null || ! tile . light . visible || tile . light . culledLight
| | ! tile . light . data . raw . cast_shadow || tile . light . data . raw . strength == 0 ) {
tile . unlockLight = true ;
tilesToRemove . push ( tile ) ;
continue ;
}
#if lnx_shadowmap_atlas_lod
var newTileSize = atlas . getTileSize ( tile . light . shadowMapScale ) ;
if ( newTileSize != tile . size ) {
if ( newTileSize == 0 ) {
tile . unlockLight = true ;
tilesToRemove . push ( tile ) ;
continue ;
}
// queue for size change
tile . newTileSize = newTileSize ;
tilesToChangeSize . push ( tile ) ;
}
#end
// set the tile offset for this tile and every linked tile to this one
var j = 0 ;
tile . forEachTileLinked ( function ( lTile ) {
tile . light . tileOffsetX [ j ] = lTile . coordsX / atlas . sizew ;
tile . light . tileOffsetY [ j ] = lTile . coordsY / atlas . sizew ;
tile . light . tileScale [ j ] = lTile . size / atlas . sizew ;
j ++ ;
} ) ;
// set shadowmap size for uniform
tile . light . data . raw . shadowmap_size = atlas . sizew ;
path . light = tile . light ;
var face = 0 ;
var faces = ShadowMapTile . tilesLightType ( tile . light . data . raw . type ) ;
#if lnx_debug
beginShadowsRenderProfile ( ) ;
#end
tile . forEachTileLinked ( function ( lTile ) {
if ( faces > 1 ) {
#if lnx_csm
switch ( tile . light . data . raw . type ) {
c ase " s u n " : tile . light . setCascade ( iron . Scene . active . camera , face ) ;
c ase " p o i n t " : path . currentFace = face ;
}
#else
path . currentFace = face ;
#end
face ++ ;
}
path . setCurrentViewportWithOffset ( lTile . size , lTile . size , lTile . coordsX , lTile . coordsY ) ;
path . drawMeshesStream ( " s h a d o w m a p _ t r a n s p a r e n t " ) ;
} ) ;
#if lnx_debug
endShadowsRenderProfile ( ) ;
#end
path . currentFace = - 1 ;
}
path . endStream ( ) ;
#if lnx_shadowmap_atlas_lod
for ( tile in tilesToChangeSize ) {
tilesToRemove . push ( tile ) ;
var newTile = ShadowMapTile . assignTiles ( tile . light , atlas , tile ) ;
if ( newTile != null )
atlas . activeTiles . push ( newTile ) ;
}
// update point light data after changing size of tiles to avoid render issues
updatePointLightAtlasData ( false ) ;
// update point light data after changing size of tiles to avoid render issues
updatePointLightAtlasData ( true ) ;
#end
for ( tile in tilesToRemove ) {
atlas . activeTiles . remove ( tile ) ;
tile . freeTile ( ) ;
}
}
#end
#end
}
#else
public static function bindShadowMap ( ) {
for ( l in iron . Scene . active . lights ) {
if ( ! l . visible || l . data . raw . type != " s u n " ) continue ;
var n = " s h a d o w M a p " ;
path . bindTarget ( n , n ) ;
var n = " s h a d o w M a p T r a n s p a r e n t " ;
path . bindTarget ( n , n ) ;
break ;
}
for ( i in 0 ... pointIndex ) {
var n = " s h a d o w M a p P o i n t [ " + i + " ] " ;
path . bindTarget ( n , n ) ;
var n = " s h a d o w M a p P o i n t T r a n s p a r e n t [ " + i + " ] " ;
path . bindTarget ( n , n ) ;
}
for ( i in 0 ... spotIndex ) {
var n = " s h a d o w M a p S p o t [ " + i + " ] " ;
path . bindTarget ( n , n ) ;
var n = " s h a d o w M a p S p o t T r a n s p a r e n t [ " + i + " ] " ;
path . bindTarget ( n , n ) ;
}
}
static function shadowMapName ( light : LightObject , transparent : Bool ) : String {
switch ( light . data . raw . type ) {
c ase " s u n " :
return transparent ? " s h a d o w M a p T r a n s p a r e n t " : " s h a d o w M a p " ;
c ase " p o i n t " :
return transparent ? " s h a d o w M a p P o i n t T r a n s p a r e n t [ " + pointIndex + " ] " : " s h a d o w M a p P o i n t [ " + pointIndex + " ] " ;
d efault :
return transparent ? " s h a d o w M a p S p o t T r a n s p a r e n t [ " + spotIndex + " ] " : " s h a d o w M a p S p o t [ " + spotIndex + " ] " ;
}
}
static function getShadowMap ( l : iron . object . LightObject , transparent : Bool ) : String {
var target = shadowMapName ( l , transparent ) ;
var rt = path . renderTargets . get ( target ) ;
// Create shadowmap on the fly
if ( rt == null ) {
if ( path . light . data . raw . shadowmap_cube ) {
// Cubemap size
var size = path . light . data . raw . shadowmap_size ;
var t = new RenderTargetRaw ( ) ;
t . name = target ;
t . width = size ;
t . height = size ;
t . format = transparent ? " R G B A 6 4 " : " D E P T H 1 6 " ;
t . is_cubemap = true ;
rt = path . createRenderTarget ( t ) ;
}
e lse { // Non-cube sm
var sizew = path . light . data . raw . shadowmap_size ;
var sizeh = sizew ;
#if lnx_csm // Cascades - atlas on x axis
if ( l . data . raw . type == " s u n " ) {
sizew = sizew * iron . object . LightObject . cascadeCount ;
}
#end
var t = new RenderTargetRaw ( ) ;
t . name = target ;
t . width = sizew ;
t . height = sizeh ;
t . format = transparent ? " R G B A 6 4 " : " D E P T H 1 6 " ;
rt = path . createRenderTarget ( t ) ;
}
}
return target ;
}
public static function drawShadowMap ( ) {
#if ( rp_shadowmap )
#if rp_probes
// Share shadow map with probe
if ( lastFrame == RenderPath . active . frame ) return ;
lastFrame = RenderPath . active . frame ;
#end
pointIndex = 0 ;
spotIndex = 0 ;
for ( l in iron . Scene . active . lights ) {
if ( ! l . visible ) continue ;
path . light = l ;
var shadowmap = Inc . getShadowMap ( l , false ) ;
var faces = l . data . raw . shadowmap_cube ? 6 : 1 ;
for ( i in 0 ... faces ) {
if ( faces > 1 ) path . currentFace = i ;
path . setTarget ( shadowmap ) ;
path . clearTarget ( null , 1.0 ) ;
if ( l . data . raw . cast_shadow ) {
path . drawMeshes ( " s h a d o w m a p " ) ;
}
}
path . currentFace = - 1 ;
if ( l . data . raw . type == " p o i n t " ) pointIndex ++ ;
e lse if ( l . data . raw . type == " s p o t " || l . data . raw . type == " a r e a " ) spotIndex ++ ;
}
#if rp_shadowmap_transparent
pointIndex = 0 ;
spotIndex = 0 ;
for ( l in iron . Scene . active . lights ) {
if ( ! l . visible ) continue ;
path . light = l ;
var shadowmap_transparent = Inc . getShadowMap ( l , true ) ;
var faces = l . data . raw . shadowmap_cube ? 6 : 1 ;
for ( i in 0 ... faces ) {
if ( faces > 1 ) path . currentFace = i ;
path . setTarget ( shadowmap_transparent ) ;
path . clearTarget ( 0xffffff , 0.0 ) ;
if ( l . data . raw . cast_shadow ) {
path . drawMeshes ( " s h a d o w m a p _ t r a n s p a r e n t " ) ;
}
}
path . currentFace = - 1 ;
if ( l . data . raw . type == " p o i n t " ) pointIndex ++ ;
e lse if ( l . data . raw . type == " s p o t " || l . data . raw . type == " a r e a " ) spotIndex ++ ;
}
#end
#end // rp_shadowmap
}
#end
public static function applyConfig ( ) {
#if lnx_config
var config = leenkx . data . Config . raw ;
// Resize shadow map
var l = path . light ;
if ( l . data . raw . type == " s u n " && l . data . raw . shadowmap_size != config . rp_shadowmap_cascade ) {
l . data . raw . shadowmap_size = config . rp_shadowmap_cascade ;
var rt = path . renderTargets . get ( " s h a d o w M a p " ) ;
if ( rt != null ) {
rt . unload ( ) ;
path . renderTargets . remove ( " s h a d o w M a p " ) ;
}
}
e lse if ( l . data . raw . shadowmap_size != config . rp_shadowmap_cube ) {
l . data . raw . shadowmap_size = config . rp_shadowmap_cube ;
var rt = path . renderTargets . get ( " s h a d o w M a p C u b e " ) ;
if ( rt != null ) {
rt . unload ( ) ;
path . renderTargets . remove ( " s h a d o w M a p C u b e " ) ;
}
}
if ( superSample != config . rp_supersample ) {
superSample = config . rp_supersample ;
for ( rt in path . renderTargets ) {
if ( rt . raw . width == 0 && rt . raw . scale != null ) {
rt . raw . scale = getSuperSampling ( ) ;
}
}
path . resize ( ) ;
}
// Init voxels
#if ( rp_voxels != ' O f f ' )
if ( ! voxelsCreated ) initGI ( ) ;
#end
#end // lnx_config
}
#if ( rp_translucency )
public static function initTranslucency ( ) {
path . createDepthBuffer ( " m a i n " , " D E P T H 2 4 " ) ;
var t = new RenderTargetRaw ( ) ;
t . name = " a c c u m " ;
t . width = 0 ;
t . height = 0 ;
t . displayp = getDisplayp ( ) ;
t . format = " R G B A 6 4 " ;
t . scale = getSuperSampling ( ) ;
t . depth_buffer = " m a i n " ;
path . createRenderTarget ( t ) ;
var t = new RenderTargetRaw ( ) ;
t . name = " r e v e a l a g e " ;
t . width = 0 ;
t . height = 0 ;
t . displayp = getDisplayp ( ) ;
t . format = " R 1 6 " ;
t . scale = getSuperSampling ( ) ;
t . depth_buffer = " m a i n " ;
path . createRenderTarget ( t ) ;
path . loadShader ( " s h a d e r _ d a t a s / t r a n s l u c e n t _ r e s o l v e / t r a n s l u c e n t _ r e s o l v e " ) ;
}
public static function drawTranslucency ( target : String ) {
path . setTarget ( " a c c u m " ) ;
path . clearTarget ( 0xff000000 ) ;
path . setTarget ( " r e v e a l a g e " ) ;
path . clearTarget ( 0xffffffff ) ;
path . setTarget ( " a c c u m " , [ " r e v e a l a g e " ] ) ;
#if rp_shadowmap
{
#if lnx_shadowmap_atlas
bindShadowMapAtlas ( ) ;
#else
bindShadowMap ( ) ;
#end
}
#end
#if ( rp_voxels != " O f f " )
path . bindTarget ( " v o x e l s O u t " , " v o x e l s " ) ;
#if ( rp_voxels == " V o x e l G I " || lnx_voxelgi_shadows )
path . bindTarget ( " v o x e l s S D F " , " v o x e l s S D F " ) ;
#end
#end
#if rp_ssrs
path . bindTarget ( " _ m a i n " , " g b u f f e r D " ) ;
#end
path . drawMeshes ( " t r a n s l u c e n t " ) ;
#if rp_render_to_texture
{
path . setTarget ( target ) ;
}
#else
{
path . setTarget ( " " ) ;
}
#end
path . bindTarget ( " a c c u m " , " g b u f f e r 0 " ) ;
path . bindTarget ( " r e v e a l a g e " , " g b u f f e r 1 " ) ;
path . drawShader ( " s h a d e r _ d a t a s / t r a n s l u c e n t _ r e s o l v e / t r a n s l u c e n t _ r e s o l v e " ) ;
}
#end
#if rp_bloom
public static inline function drawBloom ( srcRTName : String , downsampler : Downsampler , upsampler : Upsampler ) {
if ( leenkx . data . Config . raw . rp_bloom != false ) {
// This can result in little jumps in the perceived bloom radius
// when resizing the window because numMips might change, but
// all implementations using this approach have the same problem
// (including Eevee)
final minDim = Math . min ( path . currentW , path . currentH ) ;
final logMinDim = Math . max ( 1.0 , Helper . log2 ( minDim ) + ( Main . bloomRadius - 8.0 ) ) ;
final numMips = Std . int ( logMinDim ) ;
// Sample scale for upsampling, 0.5 to use half-texel steps,
// use fraction of logMinDim to make the visual jumps
// described above less visible
Postprocess . bloom_uniforms [ 3 ] = 0.5 + logMinDim - numMips ;
downsampler . dispatch ( srcRTName , numMips ) ;
upsampler . dispatch ( srcRTName , numMips ) ;
}
}
#end
#if ( rp_voxels != ' O f f ' )
public static function initGI ( tname = " v o x e l s " ) {
var t = new RenderTargetRaw ( ) ;
t . name = tname ;
#if lnx_config
var config = leenkx . data . Config . raw ;
if ( config . rp_voxels != true || voxelsCreated ) return ;
voxelsCreated = true ;
#end
var res = iron . RenderPath . getVoxelRes ( ) ;
var resZ = iron . RenderPath . getVoxelResZ ( ) ;
if ( t . name == " v o x e l s _ d i f f u s e " || t . name == " v o x e l s _ s p e c u l a r " || t . name == " v o x e l s _ a o " ) {
t . width = 0 ;
t . height = 0 ;
t . displayp = getDisplayp ( ) ;
t . format = " R G B A 3 2 " ;
}
e lse {
if ( t . name == " v o x e l s S D F " || t . name == " v o x e l s S D F t m p " ) {
t . format = " R 1 6 " ;
t . width = res ;
t . height = res * Main . voxelgiClipmapCount ;
t . depth = res ;
}
e lse {
#if ( rp_voxels == " V o x e l A O " )
{
if ( t . name == " v o x e l s O u t " || t . name == " v o x e l s O u t B " ) {
t . format = " R 1 6 " ;
t . width = res * ( 6 + 16 ) ;
t . height = res * Main . voxelgiClipmapCount ;
t . depth = res ;
}
e lse {
t . format = " R 3 2 U I " ;
t . width = res * 6 ;
t . height = res ;
t . depth = res * 2 ;
}
}
#else
{
if ( t . name == " v o x e l s O u t " || t . name == " v o x e l s O u t B " ) {
t . format = " R G B A 6 4 " ;
t . width = res * ( 6 + 16 ) ;
t . height = res * Main . voxelgiClipmapCount ;
t . depth = res ;
}
e lse {
t . format = " R 3 2 U I " ;
t . width = res * 6 ;
t . height = res ;
t . depth = res * 16 ;
}
}
#end
}
}
t . is_image = true ;
t . mipmaps = true ;
path . createRenderTarget ( t ) ;
}
#end
public static inline function getCubeSize ( ) : Int {
#if ( rp_shadowmap_cube == 256 )
return 256 ;
#elseif ( rp_shadowmap_cube == 512 )
return 512 ;
#elseif ( rp_shadowmap_cube == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_cube == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_cube == 4096 )
return 4096 ;
#else
return 0 ;
#end
}
public static inline function getCascadeSize ( ) : Int {
#if ( rp_shadowmap_cascade == 256 )
return 256 ;
#elseif ( rp_shadowmap_cascade == 512 )
return 512 ;
#elseif ( rp_shadowmap_cascade == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_cascade == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_cascade == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_cascade == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_cascade == 16384 )
return 16384 ;
#else
return 0 ;
#end
}
public static inline function getSuperSampling ( ) : Float {
return superSample ;
}
public static inline function getHdrFormat ( ) : String {
#if rp_hdr
return " R G B A 6 4 " ;
#else
return " R G B A 3 2 " ;
#end
}
public static inline function getDisplayp ( ) : Null < Int > {
#if rp_resolution_filter // Custom resolution set
return Main . resolutionSize ;
#else
return null ;
#end
}
#if lnx_debug
public static var shadowsLogicTime = 0.0 ;
public static var shadowsRenderTime = 0.0 ;
static var startShadowsLogicTime = 0.0 ;
static var startShadowsRenderTime = 0.0 ;
static var callBackSetup = false ;
static function setupEndFrameCallback ( ) {
if ( ! callBackSetup ) {
callBackSetup = true ;
iron . App . endFrameCallbacks . push ( endFrame ) ;
}
}
static function beginShadowsLogicProfile ( ) { setupEndFrameCallback ( ) ; startShadowsLogicTime = kha . Scheduler . realTime ( ) ; }
static function beginShadowsRenderProfile ( ) { startShadowsRenderTime = kha . Scheduler . realTime ( ) ; }
static function endShadowsLogicProfile ( ) { shadowsLogicTime += kha . Scheduler . realTime ( ) - startShadowsLogicTime - shadowsRenderTime ; }
static function endShadowsRenderProfile ( ) { shadowsRenderTime += kha . Scheduler . realTime ( ) - startShadowsRenderTime ; }
public static function endFrame ( ) { shadowsLogicTime = 0 ; shadowsRenderTime = 0 ; }
#end
#if ( rp_voxels != " O f f " )
public static function computeVoxelsBegin ( ) {
if ( voxel_sh0 == null )
{
voxel_sh0 = path . getComputeShader ( " v o x e l _ o f f s e t p r e v " ) ;
voxel_ta0 = voxel_sh0 . getTextureUnit ( " v o x e l s B " ) ;
voxel_tb0 = voxel_sh0 . getTextureUnit ( " v o x e l s O u t " ) ;
voxel_ca0 = voxel_sh0 . getConstantLocation ( " c l i p m a p s " ) ;
voxel_cb0 = voxel_sh0 . getConstantLocation ( " c l i p m a p L e v e l " ) ;
}
if ( voxel_sh1 == null )
{
voxel_sh1 = path . getComputeShader ( " v o x e l _ t e m p o r a l " ) ;
voxel_ta1 = voxel_sh1 . getTextureUnit ( " v o x e l s " ) ;
voxel_tb1 = voxel_sh1 . getTextureUnit ( " v o x e l s B " ) ;
voxel_tc1 = voxel_sh1 . getTextureUnit ( " v o x e l s O u t " ) ;
voxel_ca1 = voxel_sh1 . getConstantLocation ( " c l i p m a p s " ) ;
voxel_cb1 = voxel_sh1 . getConstantLocation ( " c l i p m a p L e v e l " ) ;
voxel_cc1 = voxel_sh1 . getConstantLocation ( " e n v m a p S t r e n g t h " ) ;
#if ( rp_voxels == " V o x e l G I " )
voxel_td1 = voxel_sh1 . getTextureUnit ( " v o x e l s S a m p l e r " ) ;
voxel_te1 = voxel_sh1 . getTextureUnit ( " S D F " ) ;
voxel_cc1 = voxel_sh1 . getConstantLocation ( " e n v m a p S t r e n g t h " ) ;
#else
#if lnx_voxelgi_shadows
voxel_te1 = voxel_sh1 . getTextureUnit ( " S D F " ) ;
#end
#end
}
#if ( lnx_voxelgi_shadows || rp_voxels == " V o x e l G I " )
if ( voxel_sh2 == null )
{
voxel_sh2 = path . getComputeShader ( " v o x e l _ s d f _ j u m p f l o o d " ) ;
voxel_ta2 = voxel_sh2 . getTextureUnit ( " v o x e l s S D F " ) ;
voxel_tb2 = voxel_sh2 . getTextureUnit ( " v o x e l s S D F t m p " ) ;
voxel_ca2 = voxel_sh2 . getConstantLocation ( " c l i p m a p s " ) ;
voxel_cb2 = voxel_sh2 . getConstantLocation ( " c l i p m a p L e v e l " ) ;
voxel_cc2 = voxel_sh2 . getConstantLocation ( " j u m p _ s i z e " ) ;
}
#end
if ( voxel_sh3 == null )
{
#if ( rp_voxels == " V o x e l A O " )
voxel_sh3 = path . getComputeShader ( " v o x e l _ r e s o l v e _ a o " ) ;
#else
voxel_sh3 = path . getComputeShader ( " v o x e l _ r e s o l v e _ d i f f u s e " ) ;
#end
voxel_ta3 = voxel_sh3 . getTextureUnit ( " v o x e l s " ) ;
voxel_tb3 = voxel_sh3 . getTextureUnit ( " g b u f f e r D " ) ;
voxel_tc3 = voxel_sh3 . getTextureUnit ( " g b u f f e r 0 " ) ;
#if ( rp_voxels == " V o x e l A O " )
voxel_td3 = voxel_sh3 . getTextureUnit ( " v o x e l s _ a o " ) ;
#else
voxel_td3 = voxel_sh3 . getTextureUnit ( " v o x e l s _ d i f f u s e " ) ;
#end
voxel_te3 = voxel_sh3 . getTextureUnit ( " g b u f f e r 1 " ) ;
voxel_tf3 = voxel_sh3 . getTextureUnit ( " g b u f f e r 2 " ) ;
#if lnx_brdf
voxel_tg3 = voxel_sh3 . getTextureUnit ( " s e n v m a p B r d f " ) ;
#end
#if lnx_radiance
voxel_th3 = voxel_sh3 . getTextureUnit ( " s e n v m a p R a d i a n c e " ) ;
#end
voxel_ca3 = voxel_sh3 . getConstantLocation ( " c l i p m a p s " ) ;
voxel_cb3 = voxel_sh3 . getConstantLocation ( " I n v V P " ) ;
voxel_cc3 = voxel_sh3 . getConstantLocation ( " e y e " ) ;
voxel_cd3 = voxel_sh3 . getConstantLocation ( " p o s t p r o c e s s _ r e s o l u t i o n " ) ;
voxel_ce3 = voxel_sh3 . getConstantLocation ( " e n v m a p S t r e n g t h " ) ;
#if lnx_irradiance
voxel_cf3 = voxel_sh3 . getConstantLocation ( " s h i r r " ) ;
#end
#if lnx_radiance
voxel_cg3 = voxel_sh3 . getConstantLocation ( " e n v m a p N u m M i p m a p s " ) ;
#end
#if lnx_envcol
voxel_ch3 = voxel_sh3 . getConstantLocation ( " b a c k g r o u n d C o l " ) ;
#end
}
#if ( rp_voxels == " V o x e l G I " )
if ( voxel_sh4 == null )
{
voxel_sh4 = path . getComputeShader ( " v o x e l _ r e s o l v e _ s p e c u l a r " ) ;
voxel_ta4 = voxel_sh4 . getTextureUnit ( " v o x e l s " ) ;
voxel_tb4 = voxel_sh4 . getTextureUnit ( " g b u f f e r D " ) ;
voxel_tc4 = voxel_sh4 . getTextureUnit ( " g b u f f e r 0 " ) ;
voxel_td4 = voxel_sh4 . getTextureUnit ( " v o x e l s S D F " ) ;
voxel_te4 = voxel_sh4 . getTextureUnit ( " v o x e l s _ s p e c u l a r " ) ;
voxel_tf4 = voxel_sh4 . getTextureUnit ( " s v e l o c " ) ;
voxel_ca4 = voxel_sh4 . getConstantLocation ( " c l i p m a p s " ) ;
voxel_cb4 = voxel_sh4 . getConstantLocation ( " I n v V P " ) ;
voxel_cc4 = voxel_sh4 . getConstantLocation ( " e y e " ) ;
voxel_cd4 = voxel_sh4 . getConstantLocation ( " p o s t p r o c e s s _ r e s o l u t i o n " ) ;
}
#end
}
public static function computeVoxelsOffsetPrev ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
kha . compute . Compute . setShader ( voxel_sh0 ) ;
kha . compute . Compute . setTexture ( voxel_ta0 , rts . get ( " v o x e l s O u t " ) . image , kha . compute . Access . Read ) ;
kha . compute . Compute . setTexture ( voxel_tb0 , rts . get ( " v o x e l s O u t B " ) . image , kha . compute . Access . Write ) ;
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca0 , fa ) ;
kha . compute . Compute . setInt ( voxel_cb0 , iron . RenderPath . clipmapLevel ) ;
kha . compute . Compute . compute ( Std . int ( res / 8 ) , Std . int ( res / 8 ) , Std . int ( res / 8 ) ) ;
}
public static function computeVoxelsTemporal ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var camera = iron . Scene . active . camera ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
kha . compute . Compute . setShader ( voxel_sh1 ) ;
kha . compute . Compute . setTexture ( voxel_ta1 , rts . get ( " v o x e l s " ) . image , kha . compute . Access . Read ) ;
kha . compute . Compute . setTexture ( voxel_tb1 , rts . get ( " v o x e l s O u t B " ) . image , kha . compute . Access . Read ) ;
kha . compute . Compute . setTexture ( voxel_tc1 , rts . get ( " v o x e l s O u t " ) . image , kha . compute . Access . Write ) ;
#if ( rp_voxels == " V o x e l G I " )
kha . compute . Compute . setSampledTexture ( voxel_td1 , rts . get ( " v o x e l s O u t B " ) . image ) ;
kha . compute . Compute . setTexture ( voxel_te1 , rts . get ( " v o x e l s S D F " ) . image , kha . compute . Access . Write ) ;
kha . compute . Compute . setFloat ( voxel_cc1 , iron . Scene . active . world == null ? 0.0 : iron . Scene . active . world . probe . raw . strength ) ;
#else
#if lnx_voxelgi_shadows
kha . compute . Compute . setTexture ( voxel_te1 , rts . get ( " v o x e l s S D F " ) . image , kha . compute . Access . Write ) ;
#end
#end
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca1 , fa ) ;
kha . compute . Compute . setInt ( voxel_cb1 , iron . RenderPath . clipmapLevel ) ;
kha . compute . Compute . setFloat ( voxel_cc1 , iron . Scene . active . world == null ? 0.0 : iron . Scene . active . world . probe . raw . strength ) ;
kha . compute . Compute . compute ( Std . int ( res / 8 ) , Std . int ( res / 8 ) , Std . int ( res / 8 ) ) ;
}
#if ( lnx_voxelgi_shadows || ( rp_voxels == " V o x e l G I " ) )
public static function computeVoxelsSDF ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
var read_sdf = " v o x e l s S D F " ;
var write_sdf = " v o x e l s S D F t m p " ;
var passcount = Std . int ( Math . ceil ( Math . log ( res ) / Math . log ( 2.0 ) ) ) ;
for ( i in 0 ... passcount ) {
kha . compute . Compute . setShader ( voxel_sh2 ) ;
kha . compute . Compute . setTexture ( voxel_ta2 , rts . get ( read_sdf ) . image , kha . compute . Access . Read ) ;
kha . compute . Compute . setTexture ( voxel_tb2 , rts . get ( write_sdf ) . image , kha . compute . Access . Write ) ;
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca2 , fa ) ;
kha . compute . Compute . setInt ( voxel_cb2 , iron . RenderPath . clipmapLevel ) ;
var jump_size = Math . pow ( 2.0 , passcount - i - 1 ) ;
kha . compute . Compute . setFloat ( voxel_cc2 , jump_size ) ;
kha . compute . Compute . compute ( Std . int ( res / 8 ) , Std . int ( res / 8 ) , Std . int ( res / 8 ) ) ;
if ( i < passcount - 1 )
{
read_sdf = read_sdf == " v o x e l s S D F " ? " v o x e l s S D F t m p " : " v o x e l s S D F " ;
write_sdf = write_sdf == " v o x e l s S D F " ? " v o x e l s S D F t m p " : " v o x e l s S D F " ;
}
}
}
#end
#if ( rp_voxels == " V o x e l A O " )
public static function resolveAO ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var camera = iron . Scene . active . camera ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
kha . compute . Compute . setShader ( voxel_sh3 ) ;
kha . compute . Compute . setSampledTexture ( voxel_ta3 , rts . get ( " v o x e l s O u t " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tb3 , rts . get ( " h a l f " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tc3 , rts . get ( " g b u f f e r 0 " ) . image ) ;
kha . compute . Compute . setTexture ( voxel_td3 , rts . get ( " v o x e l s _ a o " ) . image , kha . compute . Access . Write ) ;
kha . compute . Compute . setSampledTexture ( voxel_te3 , rts . get ( " g b u f f e r 1 " ) . image ) ;
#if rp_gbuffer2
kha . compute . Compute . setSampledTexture ( voxel_tf3 , rts . get ( " g b u f f e r 2 " ) . image ) ;
#end
#if lnx_brdf
kha . compute . Compute . setSampledTexture ( voxel_tg3 , iron . Scene . active . embedded . get ( " b r d f . p n g " ) ) ;
#end
#if lnx_radiance
kha . compute . Compute . setSampledTexture ( voxel_th3 , iron . Scene . active . world . probe . radiance ) ;
#end
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca3 , fa ) ;
#if lnx_centerworld
m . setFrom ( vmat ( camera . V ) ) ;
#else
m . setFrom ( camera . V ) ;
#end
m . multmat ( camera . P ) ;
m . getInverse ( m ) ;
kha . compute . Compute . setMatrix ( voxel_cb3 , m . self ) ;
kha . compute . Compute . setFloat3 ( voxel_cc3 , camera . transform . worldx ( ) , camera . transform . worldy ( ) , camera . transform . worldz ( ) ) ;
var width = iron . App . w ( ) ;
var height = iron . App . h ( ) ;
var dp = getDisplayp ( ) ;
if ( dp != null ) { // 1080p/..
if ( width > height ) {
width = Std . int ( width * ( dp / height ) * Inc . getSuperSampling ( ) ) ;
height = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
e lse {
height = Std . int ( height * ( dp / width ) * Inc . getSuperSampling ( ) ) ;
width = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
}
kha . compute . Compute . setFloat2 ( voxel_cd3 , width , height ) ;
kha . compute . Compute . setFloat ( voxel_ce3 , iron . Scene . active . world == null ? 0.0 : iron . Scene . active . world . probe . raw . strength ) ;
#if lnx_irradiance
var irradiance = iron . Scene . active . world == null ?
iron . data . WorldData . getEmptyIrradiance ( ) :
iron . Scene . active . world . probe . irradiance ;
kha . compute . Compute . setFloats ( voxel_cf3 , irradiance ) ;
#end
#if lnx_radiance
kha . compute . Compute . setFloat ( voxel_cg3 , iron . Scene . active . world != null ? iron . Scene . active . world . probe . raw . radiance_mipmaps + 1 - 2 : 1 ) ;
#end
#if lnx_envcol
var x: kha . FastFloat = 0.0 ;
var y: kha . FastFloat = 0.0 ;
var z: kha . FastFloat = 0.0 ;
if ( camera . data . raw . clear_color != null ) {
x = camera . data . raw . clear_color [ 0 ] ;
y = camera . data . raw . clear_color [ 1 ] ;
z = camera . data . raw . clear_color [ 2 ] ;
}
kha . compute . Compute . setFloat3 ( voxel_ch3 , x , y , z ) ;
#end
kha . compute . Compute . compute ( Std . int ( ( width + 7 ) / 8 ) , Std . int ( ( height + 7 ) / 8 ) , 1 ) ;
}
#else
public static function resolveDiffuse ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var camera = iron . Scene . active . camera ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
kha . compute . Compute . setShader ( voxel_sh3 ) ;
kha . compute . Compute . setSampledTexture ( voxel_ta3 , rts . get ( " v o x e l s O u t " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tb3 , rts . get ( " h a l f " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tc3 , rts . get ( " g b u f f e r 0 " ) . image ) ;
kha . compute . Compute . setTexture ( voxel_td3 , rts . get ( " v o x e l s _ d i f f u s e " ) . image , kha . compute . Access . Write ) ;
kha . compute . Compute . setSampledTexture ( voxel_te3 , rts . get ( " g b u f f e r 1 " ) . image ) ;
#if rp_gbuffer2
kha . compute . Compute . setSampledTexture ( voxel_tf3 , rts . get ( " g b u f f e r 2 " ) . image ) ;
#end
#if lnx_brdf
kha . compute . Compute . setSampledTexture ( voxel_tg3 , iron . Scene . active . embedded . get ( " b r d f . p n g " ) ) ;
#end
#if lnx_radiance
kha . compute . Compute . setSampledTexture ( voxel_th3 , iron . Scene . active . world . probe . radiance ) ;
#end
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca3 , fa ) ;
#if lnx_centerworld
m . setFrom ( vmat ( camera . V ) ) ;
#else
m . setFrom ( camera . V ) ;
#end
m . multmat ( camera . P ) ;
m . getInverse ( m ) ;
kha . compute . Compute . setMatrix ( voxel_cb3 , m . self ) ;
kha . compute . Compute . setFloat3 ( voxel_cc3 , camera . transform . worldx ( ) , camera . transform . worldy ( ) , camera . transform . worldz ( ) ) ;
var width = iron . App . w ( ) ;
var height = iron . App . h ( ) ;
var dp = getDisplayp ( ) ;
if ( dp != null ) { // 1080p/..
if ( width > height ) {
width = Std . int ( width * ( dp / height ) * Inc . getSuperSampling ( ) ) ;
height = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
e lse {
height = Std . int ( height * ( dp / width ) * Inc . getSuperSampling ( ) ) ;
width = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
}
kha . compute . Compute . setFloat2 ( voxel_cd3 , width , height ) ;
kha . compute . Compute . setFloat ( voxel_ce3 , iron . Scene . active . world == null ? 0.0 : iron . Scene . active . world . probe . raw . strength ) ;
#if lnx_irradiance
var irradiance = iron . Scene . active . world == null ?
iron . data . WorldData . getEmptyIrradiance ( ) :
iron . Scene . active . world . probe . irradiance ;
kha . compute . Compute . setFloats ( voxel_cf3 , irradiance ) ;
#end
#if lnx_radiance
kha . compute . Compute . setFloat ( voxel_cg3 , iron . Scene . active . world != null ? iron . Scene . active . world . probe . raw . radiance_mipmaps + 1 - 2 : 1 ) ;
#end
#if lnx_envcol
var x: kha . FastFloat = 0.0 ;
var y: kha . FastFloat = 0.0 ;
var z: kha . FastFloat = 0.0 ;
if ( camera . data . raw . clear_color != null ) {
x = camera . data . raw . clear_color [ 0 ] ;
y = camera . data . raw . clear_color [ 1 ] ;
z = camera . data . raw . clear_color [ 2 ] ;
}
kha . compute . Compute . setFloat3 ( voxel_ch3 , x , y , z ) ;
#end
kha . compute . Compute . compute ( Std . int ( ( width + 7 ) / 8 ) , Std . int ( ( height + 7 ) / 8 ) , 1 ) ;
}
public static function resolveSpecular ( ) {
var rts = path . renderTargets ;
var res = iron . RenderPath . getVoxelRes ( ) ;
var camera = iron . Scene . active . camera ;
var clipmaps = iron . RenderPath . clipmaps ;
var clipmap = clipmaps [ iron . RenderPath . clipmapLevel ] ;
kha . compute . Compute . setShader ( voxel_sh4 ) ;
kha . compute . Compute . setSampledTexture ( voxel_ta4 , rts . get ( " v o x e l s O u t " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tb4 , rts . get ( " h a l f " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_tc4 , rts . get ( " g b u f f e r 0 " ) . image ) ;
kha . compute . Compute . setSampledTexture ( voxel_td4 , rts . get ( " v o x e l s S D F " ) . image ) ;
kha . compute . Compute . setTexture ( voxel_te4 , rts . get ( " v o x e l s _ s p e c u l a r " ) . image , kha . compute . Access . Write ) ;
#if rp_gbuffer2
kha . compute . Compute . setSampledTexture ( voxel_tf4 , rts . get ( " g b u f f e r 2 " ) . image ) ;
#end
var fa: Float32Array = new Float32Array ( Main . voxelgiClipmapCount * 10 ) ;
for ( i in 0 ... Main . voxelgiClipmapCount ) {
fa [ i * 10 ] = clipmaps [ i ] . voxelSize ;
fa [ i * 10 + 1 ] = clipmaps [ i ] . extents . x ;
fa [ i * 10 + 2 ] = clipmaps [ i ] . extents . y ;
fa [ i * 10 + 3 ] = clipmaps [ i ] . extents . z ;
fa [ i * 10 + 4 ] = clipmaps [ i ] . center . x ;
fa [ i * 10 + 5 ] = clipmaps [ i ] . center . y ;
fa [ i * 10 + 6 ] = clipmaps [ i ] . center . z ;
fa [ i * 10 + 7 ] = clipmaps [ i ] . offset_prev . x ;
fa [ i * 10 + 8 ] = clipmaps [ i ] . offset_prev . y ;
fa [ i * 10 + 9 ] = clipmaps [ i ] . offset_prev . z ;
}
kha . compute . Compute . setFloats ( voxel_ca4 , fa ) ;
#if lnx_centerworld
m . setFrom ( vmat ( camera . V ) ) ;
#else
m . setFrom ( camera . V ) ;
#end
m . multmat ( camera . P ) ;
m . getInverse ( m ) ;
kha . compute . Compute . setMatrix ( voxel_cb4 , m . self ) ;
kha . compute . Compute . setFloat3 ( voxel_cc4 , camera . transform . worldx ( ) , camera . transform . worldy ( ) , camera . transform . worldz ( ) ) ;
var width = iron . App . w ( ) ;
var height = iron . App . h ( ) ;
var dp = getDisplayp ( ) ;
if ( dp != null ) { // 1080p/..
if ( width > height ) {
width = Std . int ( width * ( dp / height ) * Inc . getSuperSampling ( ) ) ;
height = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
e lse {
height = Std . int ( height * ( dp / width ) * Inc . getSuperSampling ( ) ) ;
width = Std . int ( dp * Inc . getSuperSampling ( ) ) ;
}
}
kha . compute . Compute . setFloat2 ( voxel_cd4 , width , height ) ;
kha . compute . Compute . compute ( Std . int ( ( width + 7 ) / 8 ) , Std . int ( ( height + 7 ) / 8 ) , 1 ) ;
}
#end // GI
#end // Voxels
2025-01-22 16:18:30 +01:00
}
#if lnx_shadowmap_atlas
class ShadowMapAtlas {
2025-05-28 01:36:04 +00:00
public var target: String ;
public var baseTileSizeConst: Int ;
public var maxAtlasSizeConst: Int ;
public var sizew: Int ;
public var sizeh: Int ;
public var currTileOffset = 0 ;
public var tiles: Array < ShadowMapTile > = [ ] ;
public var activeTiles: Array < ShadowMapTile > = [ ] ;
public var depth = 1 ;
#if lnx_shadowmap_atlas_lod
var tileSizes: Array < Int > = [ ] ;
var tileSizeFactor: Array < Float > = [ ] ;
#end
public var updateRenderTarget = false ;
public static var shadowMapAtlases: Map < String , ShadowMapAtlas > = new Map ( ) ; // map a shadowmap atlas to their light type
public static var shadowMapAtlasesTransparent: Map < String , ShadowMapAtlas > = new Map ( ) ; // map a shadowmap atlas to their light type
#if lnx_debug
public var lightType: String ;
public var rejectedLights: Array < LightObject > = [ ] ;
#end
function n e w ( light : LightObject , transparent : Bool ) {
var maxTileSize = shadowMapAtlasSize ( light ) ;
this . target = shadowMapAtlasName ( light . data . raw . type , transparent ) ;
this . sizew = this . sizeh = this . baseTileSizeConst = maxTileSize ;
this . depth = getSubdivisions ( ) ;
this . maxAtlasSizeConst = getMaxAtlasSize ( light . data . raw . type ) ;
#if lnx_shadowmap_atlas_lod
computeTileSizes ( maxTileSize , depth ) ;
#end
#if lnx_debug
#if lnx_shadowmap_atlas_single_map
this . lightType = " a n y " ;
#else
this . lightType = light . data . raw . type ;
#end
#end
}
/ * *
* Adds a light to an atlas . The atlas is decided based on the type of the light
* @ param light of type LightObject to be added to an yatlas
* @ return if t h e l i g h t w a s a d d e d s u c c e s f u l l y
* /
public static function addLight ( light : LightObject , transparent : Bool ) {
var atlasName = shadowMapAtlasName ( light . data . raw . type , transparent ) ;
var atlas = transparent ? shadowMapAtlasesTransparent . get ( atlasName ) : shadowMapAtlases . get ( atlasName ) ;
if ( atlas == null ) {
// create a new atlas
atlas = new ShadowMapAtlas ( light , transparent ) ;
if ( transparent )
shadowMapAtlasesTransparent . set ( atlasName , atlas ) ;
e lse
shadowMapAtlases . set ( atlasName , atlas ) ;
}
// find a free tile for this light
var mainTile = ShadowMapTile . assignTiles ( light , atlas , null ) ;
if ( mainTile == null ) {
#if lnx_debug
if ( ! atlas . rejectedLights . contains ( light ) )
atlas . rejectedLights . push ( light ) ;
#end
return ;
}
atlas . activeTiles . push ( mainTile ) ;
// notify the tile on light remove
light . tileNotifyOnRemove = mainTile . notifyOnLightRemove ;
// notify atlas when this tile is freed
mainTile . notifyOnFree = atlas . freeActiveTile ;
// "lock" light to make sure it's not eligible to be added again
if ( transparent )
light . lightInAtlasTransparent = true ;
e lse
light . lightInAtlas = true ;
}
static inline function shadowMapAtlasSize ( light : LightObject ) : Int {
// TODO: this can break because we are changing shadowmap_size elsewhere.
return light . data . raw . shadowmap_size ;
}
public function getTileSize ( shadowMapScale : Float ) : Int {
#if lnx_shadowmap_atlas_lod
// find the first scale factor that is smaller to the shadowmap scale, and then return the previous one.
var i = 0 ;
for ( sizeFactor in tileSizeFactor ) {
if ( sizeFactor < shadowMapScale ) break ;
i ++ ;
}
return tileSizes [ i - 1 ] ;
#else
return this . baseTileSizeConst ;
#end
}
#if lnx_shadowmap_atlas_lod
function computeTileSizes ( maxTileSize : Int , depth : Int ) : Void {
// find the highest value based on the calculation done in the cluster code
var base = LightObject . zToShadowMapScale ( 0 , 16 ) ;
var subdiv = base / depth ;
for ( i in 0 ... depth ) {
this . tileSizes . push ( Std . int ( maxTileSize / Math . pow ( 2 , i ) ) ) ;
this . tileSizeFactor . push ( base ) ;
base -= subdiv ;
}
this . tileSizes . push ( 0 ) ;
this . tileSizeFactor . push ( 0.0 ) ;
}
#end
public inline function atlasLimitReached ( ) {
// asume square atlas
return ( currTileOffset + 1 ) * baseTileSizeConst > maxAtlasSizeConst ;
}
public static inline function shadowMapAtlasName ( type : String , transparent : Bool ) : String {
#if lnx_shadowmap_atlas_single_map
return " s h a d o w M a p A t l a s " ;
#else
switch ( type ) {
c ase " p o i n t " :
return transparent ? " s h a d o w M a p A t l a s P o i n t T r a n s p a r e n t " : " s h a d o w M a p A t l a s P o i n t " ;
c ase " s u n " :
return transparent ? " s h a d o w M a p A t l a s S u n T r a n s p a r e n t " : " s h a d o w M a p A t l a s S u n " ;
d efault :
return transparent ? " s h a d o w M a p A t l a s S p o t T r a n s p a r e n t " : " s h a d o w M a p A t l a s S p o t " ;
}
#end
}
public static inline function getSubdivisions ( ) : Int {
#if ( rp_shadowmap_atlas_lod_subdivisions == 2 )
return 2 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 3 )
return 3 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 4 )
return 4 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 5 )
return 5 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 6 )
return 6 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 7 )
return 7 ;
#elseif ( rp_shadowmap_atlas_lod_subdivisions == 8 )
return 8 ;
#elseif ( ! lnx_shadowmap_atlas_lod )
return 1 ;
#end
}
public static inline function getMaxAtlasSize ( type : String ) : Int {
#if lnx_shadowmap_atlas_single_map
#if ( rp_shadowmap_atlas_max_size == 512 )
return 512 ;
#elseif ( rp_shadowmap_atlas_max_size == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_atlas_max_size == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_atlas_max_size == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_atlas_max_size == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_atlas_max_size == 16384 )
return 16384 ;
#elseif ( rp_shadowmap_atlas_max_size == 32768 )
return 32768 ;
#end
#else
switch ( type ) {
c ase " p o i n t " : {
#if ( rp_shadowmap_atlas_max_size_point == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_atlas_max_size_point == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_atlas_max_size_point == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_atlas_max_size_point == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_atlas_max_size_point == 16384 )
return 16384 ;
#elseif ( rp_shadowmap_atlas_max_size_point == 32768 )
return 32768 ;
#end
}
c ase " s p o t " : {
#if ( rp_shadowmap_atlas_max_size_spot == 512 )
return 512 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 16384 )
return 16384 ;
#elseif ( rp_shadowmap_atlas_max_size_spot == 32768 )
return 32768 ;
#end
}
c ase " s u n " : {
#if ( rp_shadowmap_atlas_max_size_sun == 512 )
return 512 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 16384 )
return 16384 ;
#elseif ( rp_shadowmap_atlas_max_size_sun == 32768 )
return 32768 ;
#end
}
d efault : {
#if ( rp_shadowmap_atlas_max_size == 512 )
return 512 ;
#elseif ( rp_shadowmap_atlas_max_size == 1024 )
return 1024 ;
#elseif ( rp_shadowmap_atlas_max_size == 2048 )
return 2048 ;
#elseif ( rp_shadowmap_atlas_max_size == 4096 )
return 4096 ;
#elseif ( rp_shadowmap_atlas_max_size == 8192 )
return 8192 ;
#elseif ( rp_shadowmap_atlas_max_size == 16384 )
return 16384 ;
#elseif ( rp_shadowmap_atlas_max_size == 32768 )
return 32768 ;
#end
}
}
#end
}
function freeActiveTile ( tile : ShadowMapTile ) {
activeTiles . remove ( tile ) ;
}
2025-01-22 16:18:30 +01:00
}
class ShadowMapTile {
2025-05-28 01:36:04 +00:00
public var light: Null < LightObject > = null ;
public var coordsX: Int ;
public var coordsY: Int ;
public var size: Int ;
public var tiles: Array < ShadowMapTile > = [ ] ;
public var linkedTile: ShadowMapTile = null ;
#if lnx_shadowmap_atlas_lod
public var parentTile: ShadowMapTile = null ;
public var activeSubTiles: Int = 0 ;
public var newTileSize: Int = - 1 ;
static var tilePattern = [ [ 0 , 0 ] , [ 1 , 0 ] , [ 0 , 1 ] , [ 1 , 1 ] ] ;
#end
function n e w ( coordsX : Int , coordsY : Int , size : Int ) {
this . coordsX = coordsX ;
this . coordsY = coordsY ;
this . size = size ;
}
public static function assignTiles ( light : LightObject , atlas : ShadowMapAtlas , oldTile : ShadowMapTile ) : ShadowMapTile {
var tileSize = 0 ;
#if lnx_shadowmap_atlas_lod
if ( oldTile != null && oldTile . newTileSize != - 1 ) {
// reuse tilesize instead of computing it again
tileSize = oldTile . newTileSize ;
oldTile . newTileSize = - 1 ;
}
e lse
#end
tileSize = atlas . getTileSize ( light . shadowMapScale ) ;
if ( tileSize == 0 )
return null ;
var tiles = [ ] ;
tiles = findCreateTiles ( light , oldTile , atlas , tilesLightType ( light . data . raw . type ) , tileSize ) ;
// lock new tiles with light
for ( tile in tiles )
tile . lockTile ( light ) ;
return linkTiles ( tiles ) ;
}
static inline function linkTiles ( tiles : Array < ShadowMapTile > ) : ShadowMapTile {
if ( tiles . length > 1 ) {
var linkedTile = tiles [ 0 ] ;
for ( i in 1 ... tiles . length ) {
linkedTile . linkedTile = tiles [ i ] ;
linkedTile = tiles [ i ] ;
}
}
return tiles [ 0 ] ;
}
static inline function findCreateTiles ( light : LightObject , oldTile : ShadowMapTile , atlas : ShadowMapAtlas , tilesPerLightType : Int , tileSize : Int ) : Array < ShadowMapTile > {
var tilesFound: Array < ShadowMapTile > = [ ] ;
while ( tilesFound . length < tilesPerLightType ) {
findTiles ( light , oldTile , atlas . tiles , tileSize , tilesPerLightType , tilesFound ) ;
if ( tilesFound . length < tilesPerLightType ) {
tilesFound = [ ] ; // empty tilesFound
// skip creating more tiles if limit has been reached
if ( atlas . atlasLimitReached ( ) )
break ;
createTiles ( atlas . tiles , atlas . baseTileSizeConst , atlas . depth , atlas . currTileOffset , atlas . currTileOffset ) ;
atlas . currTileOffset ++ ;
// update texture to accomodate new size
atlas . updateRenderTarget = true ;
atlas . sizew = atlas . sizeh = atlas . currTileOffset * atlas . baseTileSizeConst ;
}
}
return tilesFound ;
}
inline static function findTiles ( light : LightObject , oldTile : ShadowMapTile ,
tiles : Array < ShadowMapTile > , size : Int , tilesCount : Int , tilesFound : Array < ShadowMapTile > ) : Void {
#if lnx_shadowmap_atlas_lod
if ( oldTile != null ) {
// reuse children tiles
if ( size < oldTile . size ) {
oldTile . forEachTileLinked ( function ( lTile ) {
var childTile = findFreeChildTile ( lTile , size ) ;
tilesFound . push ( childTile ) ;
} ) ;
}
// reuse parent tiles
e lse {
oldTile . forEachTileLinked ( function ( lTile ) {
// find out if parents tiles are not occupied
var parentTile = findFreeParentTile ( lTile , size ) ;
// if parent is free, add it to found tiles
if ( parentTile != null )
tilesFound . push ( parentTile ) ;
} ) ;
if ( tilesFound . length < tilesCount ) {
// find naively the rest of the tiles that couldn't be reused
findTilesNaive ( light , tiles , size , tilesCount , tilesFound ) ;
}
}
}
e lse
#end
findTilesNaive ( light , tiles , size , tilesCount , tilesFound ) ;
}
#if lnx_shadowmap_atlas_lod
static inline function findFreeChildTile ( tile : ShadowMapTile , size : Int ) : ShadowMapTile {
var childrenTile = tile ;
while ( size < childrenTile . size ) {
childrenTile = childrenTile . tiles [ 0 ] ;
}
return childrenTile ;
}
static inline function findFreeParentTile ( tile : ShadowMapTile , size : Int ) : ShadowMapTile {
var parentTile = tile ;
while ( size > parentTile . size ) {
parentTile = parentTile . parentTile ;
// stop if parent tile is occupied
if ( parentTile . activeSubTiles > 1 ) {
parentTile = null ;
break ;
}
}
return parentTile ;
}
#end
static function findTilesNaive ( light : LightObject , tiles : Array < ShadowMapTile > , size : Int , tilesCount : Int , tilesFound : Array < ShadowMapTile > ) : Void {
for ( tile in tiles ) {
if ( tile . size == size ) {
if ( tile . light == null #if lnx_shadowmap_atlas_lod && tile . activeSubTiles == 0 #end ) {
tilesFound . push ( tile ) ;
// stop after finding enough tiles
if ( tilesFound . length == tilesCount )
return ;
}
}
e lse {
// skip over if end of the tree or tile is occupied
if ( tile . tiles . length == 0 || tile . light != null )
continue ;
findTilesNaive ( light , tile . tiles , size , tilesCount , tilesFound ) ;
// skip iterating over the rest of the tiles if found enough
if ( tilesFound . length == tilesCount )
return ;
}
}
}
// create a basic tile and subdivide it if needed
public static function createTiles ( tiles : Array < ShadowMapTile > , size : Int , depth : Int , baseX : Int , baseY : Int ) {
var i = baseX ;
var j = 0 ;
var lastTile = tiles . length ;
// assume occupied tiles start from 1 line before the base x
var occupiedTiles = baseX - 1 ;
while ( i >= 0 ) {
if ( i <= occupiedTiles ) { // avoid overriding tiles
j = baseY ;
}
while ( j <= baseY ) {
// create base tile of max-size
tiles . push ( new ShadowMapTile ( size * i , size * j , size ) ) ;
#if lnx_shadowmap_atlas_lod
tiles [ lastTile ] . tiles = subDivTile ( tiles [ lastTile ] , size , size * i , size * j , depth - 1 ) ;
#end
lastTile ++ ;
j ++ ;
}
i -- ;
}
}
#if lnx_shadowmap_atlas_lod
static function subDivTile ( parent : ShadowMapTile , size : Int , baseCoordsX : Int , baseCoordsY : Int , depth : Int ) : Array < ShadowMapTile > {
var tileSize = Std . int ( size / 2 ) ;
var tiles = [ ] ;
for ( i in 0 ... 4 ) {
var coordsX = baseCoordsX + tilePattern [ i ] [ 0 ] * tileSize ;
var coordsY = baseCoordsY + tilePattern [ i ] [ 1 ] * tileSize ;
var tile = new ShadowMapTile ( coordsX , coordsY , tileSize ) ;
tile . parentTile = parent ;
if ( depth > 1 )
tile . tiles = subDivTile ( tile , tileSize , coordsX , coordsY , depth - 1 ) ;
tiles . push ( tile ) ;
}
return tiles ;
}
#end
public static inline function tilesLightType ( type : String ) : Int {
switch ( type ) {
c ase " s u n " :
return LightObject . cascadeCount ;
c ase " p o i n t " :
return 6 ;
d efault :
return 1 ;
}
}
public function notifyOnLightRemove ( ) {
unlockLight = true ;
freeTile ( ) ;
}
inline function lockTile ( light : LightObject ) : Void {
if ( this . light != null )
return ;
this . light = light ;
#if lnx_shadowmap_atlas_lod
// update the count of used tiles for parents
this . forEachParentTile ( function ( pTile ) {
pTile . activeSubTiles ++ ;
} ) ;
#end
}
public var unlockLight: Bool = false ;
public var notifyOnFree: ShadowMapTile -> Void ;
public function freeTile ( ) : Void {
// prevent duplicates
if ( light != null && unlockLight ) {
light . lightInAtlas = false ;
unlockLight = false ;
}
var linkedTile = this ;
var tempTile = this ;
while ( linkedTile != null ) {
linkedTile . light = null ;
#if lnx_shadowmap_atlas_lod
// update the count of used tiles for parents
linkedTile . forEachParentTile ( function ( pTile ) {
if ( pTile . activeSubTiles > 0 )
pTile . activeSubTiles -- ;
} ) ;
#end
linkedTile = linkedTile . linkedTile ;
// unlink linked tiles
tempTile . linkedTile = null ;
tempTile = linkedTile ;
}
// notify atlas that this tile has been freed
if ( notifyOnFree != null ) {
notifyOnFree ( this ) ;
notifyOnFree = null ;
}
}
public inline function forEachTileLinked ( action : ShadowMapTile -> Void ) : Void {
var linkedTile = this ;
while ( linkedTile != null ) {
action ( linkedTile ) ;
linkedTile = linkedTile . linkedTile ;
}
}
#if lnx_shadowmap_atlas_lod
public inline function forEachParentTile ( action : ShadowMapTile -> Void ) : Void {
var parentTile = this . parentTile ;
while ( parentTile != null ) {
action ( parentTile ) ;
parentTile = parentTile . parentTile ;
}
}
#end
2025-01-22 16:18:30 +01:00
}
#end