From 6b25d8c8ade0f746fa974a422a144ffcc2e85859 Mon Sep 17 00:00:00 2001 From: Onek8 Date: Wed, 28 May 2025 01:36:04 +0000 Subject: [PATCH] revert 13ca31f480761f13b7d03012eedd409f3a9f9dbd revert Update leenkx/Sources/leenkx/renderpath/Inc.hx --- leenkx/Sources/leenkx/renderpath/Inc.hx | 3504 ++++++++++++----------- 1 file changed, 1755 insertions(+), 1749 deletions(-) diff --git a/leenkx/Sources/leenkx/renderpath/Inc.hx b/leenkx/Sources/leenkx/renderpath/Inc.hx index dea31e7..09dd163 100644 --- a/leenkx/Sources/leenkx/renderpath/Inc.hx +++ b/leenkx/Sources/leenkx/renderpath/Inc.hx @@ -7,1817 +7,1823 @@ import leenkx.math.Helper; import kha.arrays.Float32Array; class Inc { - 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 != 'Off') && lnx_config) - static var voxelsCreated = false; - #end - - #if (rp_voxels != "Off") - 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 == "Voxel GI") - static var voxel_td1:kha.compute.TextureUnit; - static var voxel_te1:kha.compute.TextureUnit; - #else - #if lnx_voxelgi_shadows - static var voxel_te1:kha.compute.TextureUnit; - #end - #end - #if (lnx_voxelgi_shadows || rp_voxels == "Voxel GI") - 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 == "Voxel GI") - 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 == "sun" ? - 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("point", true)) : ShadowMapAtlas.shadowMapAtlases.get(ShadowMapAtlas.shadowMapAtlasName("point", false)); - if (atlas != null) { - if(LightObject.pointLightsData == null) { - LightObject.pointLightsData = new kha.arrays.Float32Array( - LightObject.maxLightsCluster * ShadowMapTile.tilesLightType("point") * 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 == "point") { - 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 ? "RGBA64" : "DEPTH16"; - 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); - } - else 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) { - case "sun": tile.light.setCascade(iron.Scene.active.camera, face); - case "point": path.currentFace = face; - } - #else - path.currentFace = face; - #end - face++; - } - path.setCurrentViewportWithOffset(lTile.size, lTile.size, lTile.coordsX, lTile.coordsY); - - path.drawMeshesStream("shadowmap"); - }); - #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) { - case "sun": tile.light.setCascade(iron.Scene.active.camera, face); - case "point": path.currentFace = face; - } - #else - path.currentFace = face; - #end - face++; - } - path.setCurrentViewportWithOffset(lTile.size, lTile.size, lTile.coordsX, lTile.coordsY); - - path.drawMeshesStream("shadowmap_transparent"); - }); - #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 != "sun") continue; - var n = "shadowMap"; - path.bindTarget(n, n); - var n = "shadowMapTransparent"; - path.bindTarget(n, n); - break; - } - for (i in 0...pointIndex) { - var n = "shadowMapPoint[" + i + "]"; - path.bindTarget(n, n); - var n = "shadowMapPointTransparent[" + i + "]"; - path.bindTarget(n, n); - } - for (i in 0...spotIndex) { - var n = "shadowMapSpot[" + i + "]"; - path.bindTarget(n, n); - var n = "shadowMapSpotTransparent[" + i + "]"; - path.bindTarget(n, n); - } - } - - static function shadowMapName(light: LightObject, transparent: Bool): String { - switch (light.data.raw.type) { - case "sun": - return transparent ? "shadowMapTransparent" : "shadowMap"; - case "point": - return transparent ? "shadowMapPointTransparent[" + pointIndex + "]" : "shadowMapPoint[" + pointIndex + "]"; - default: - return transparent ? "shadowMapSpotTransparent[" + spotIndex + "]" : "shadowMapSpot[" + 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 ? "RGBA64" : "DEPTH16"; - t.is_cubemap = true; - rt = path.createRenderTarget(t); - } - else { // 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 == "sun") { - sizew = sizew * iron.object.LightObject.cascadeCount; - } - #end - var t = new RenderTargetRaw(); - t.name = target; - t.width = sizew; - t.height = sizeh; - t.format = transparent ? "RGBA64" : "DEPTH16"; - 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("shadowmap"); - } - } - path.currentFace = -1; - - if (l.data.raw.type == "point") pointIndex++; - else if (l.data.raw.type == "spot" || l.data.raw.type == "area") 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("shadowmap_transparent"); - } - } - path.currentFace = -1; - - if (l.data.raw.type == "point") pointIndex++; - else if (l.data.raw.type == "spot" || l.data.raw.type == "area") 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 == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) { - l.data.raw.shadowmap_size = config.rp_shadowmap_cascade; - var rt = path.renderTargets.get("shadowMap"); - if (rt != null) { - rt.unload(); - path.renderTargets.remove("shadowMap"); - } - } - else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) { - l.data.raw.shadowmap_size = config.rp_shadowmap_cube; - var rt = path.renderTargets.get("shadowMapCube"); - if (rt != null) { - rt.unload(); - path.renderTargets.remove("shadowMapCube"); - } - } - 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 != 'Off') - if (!voxelsCreated) initGI(); - #end - #end // lnx_config - } - - #if (rp_translucency) - public static function initTranslucency() { - path.createDepthBuffer("main", "DEPTH24"); - - var t = new RenderTargetRaw(); - t.name = "accum"; - t.width = 0; - t.height = 0; - t.displayp = getDisplayp(); - t.format = "RGBA64"; - t.scale = getSuperSampling(); - t.depth_buffer = "main"; - path.createRenderTarget(t); - - var t = new RenderTargetRaw(); - t.name = "revealage"; - t.width = 0; - t.height = 0; - t.displayp = getDisplayp(); - t.format = "R16"; - t.scale = getSuperSampling(); - t.depth_buffer = "main"; - path.createRenderTarget(t); - - path.loadShader("shader_datas/translucent_resolve/translucent_resolve"); - } - - public static function drawTranslucency(target: String) { - path.setTarget("accum"); - path.clearTarget(0xff000000); - path.setTarget("revealage"); - path.clearTarget(0xffffffff); - path.setTarget("accum", ["revealage"]); - - #if rp_shadowmap - { - #if lnx_shadowmap_atlas - bindShadowMapAtlas(); - #else - bindShadowMap(); - #end - } - #end - - #if (rp_voxels != "Off") - path.bindTarget("voxelsOut", "voxels"); - #if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows) - path.bindTarget("voxelsSDF", "voxelsSDF"); - #end - #end - - #if rp_ssrs - path.bindTarget("_main", "gbufferD"); - #end - - path.drawMeshes("translucent"); - - #if rp_render_to_texture - { - path.setTarget(target); - } - #else - { - path.setTarget(""); - } - #end - - path.bindTarget("accum", "gbuffer0"); - path.bindTarget("revealage", "gbuffer1"); - path.drawShader("shader_datas/translucent_resolve/translucent_resolve"); - } - #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 != 'Off') - public static function initGI(tname = "voxels") { - 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 == "voxels_diffuse" || t.name == "voxels_specular" || t.name == "voxels_ao") { - t.width = 0; - t.height = 0; - t.displayp = getDisplayp(); - t.format = "RGBA32"; - } - else { - if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") { - t.format = "R8"; - t.width = res; - t.height = res * Main.voxelgiClipmapCount; - t.depth = res; - } - else { - #if (rp_voxels == "Voxel AO") - { - if (t.name == "voxelsOut" || t.name == "voxelsOutB") { - t.format = "R8"; - t.width = res * (6 + 16); - t.height = res * Main.voxelgiClipmapCount; - t.depth = res; - } - else { - t.format = "R32UI"; - t.width = res * 6; - t.height = res; - t.depth = res * 2; - } - } - #else - { - if (t.name == "voxelsOut" || t.name == "voxelsOutB") { - t.format = "RGBA64"; - t.width = res * (6 + 16); - t.height = res * Main.voxelgiClipmapCount; - t.depth = res; - } - else { - t.format = "R32UI"; - 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 "RGBA64"; - #else - return "RGBA32"; - #end - } - - public static inline function getDisplayp(): Null { - #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 != "Off") - public static function computeVoxelsBegin() { - if (voxel_sh0 == null) - { - voxel_sh0 = path.getComputeShader("voxel_offsetprev"); - - voxel_ta0 = voxel_sh0.getTextureUnit("voxelsB"); - voxel_tb0 = voxel_sh0.getTextureUnit("voxelsOut"); - - voxel_ca0 = voxel_sh0.getConstantLocation("clipmaps"); - voxel_cb0 = voxel_sh0.getConstantLocation("clipmapLevel"); - } - if (voxel_sh1 == null) - { - voxel_sh1 = path.getComputeShader("voxel_temporal"); - voxel_ta1 = voxel_sh1.getTextureUnit("voxels"); - voxel_tb1 = voxel_sh1.getTextureUnit("voxelsB"); - voxel_tc1 = voxel_sh1.getTextureUnit("voxelsOut"); - - voxel_ca1 = voxel_sh1.getConstantLocation("clipmaps"); - voxel_cb1 = voxel_sh1.getConstantLocation("clipmapLevel"); - - #if (rp_voxels == "Voxel GI") - voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler"); - voxel_te1 = voxel_sh1.getTextureUnit("SDF"); - #else - #if lnx_voxelgi_shadows - voxel_te1 = voxel_sh1.getTextureUnit("SDF"); - #end - #end - } - #if (lnx_voxelgi_shadows || rp_voxels == "Voxel GI") - if (voxel_sh2 == null) - { - voxel_sh2 = path.getComputeShader("voxel_sdf_jumpflood"); - voxel_ta2 = voxel_sh2.getTextureUnit("voxelsSDF"); - voxel_tb2 = voxel_sh2.getTextureUnit("voxelsSDFtmp"); - - voxel_ca2 = voxel_sh2.getConstantLocation("clipmaps"); - voxel_cb2 = voxel_sh2.getConstantLocation("clipmapLevel"); - voxel_cc2 = voxel_sh2.getConstantLocation("jump_size"); - } - #end - if (voxel_sh3 == null) - { - #if (rp_voxels == "Voxel AO") - voxel_sh3 = path.getComputeShader("voxel_resolve_ao"); - #else - voxel_sh3 = path.getComputeShader("voxel_resolve_diffuse"); - #end - voxel_ta3 = voxel_sh3.getTextureUnit("voxels"); - voxel_tb3 = voxel_sh3.getTextureUnit("gbufferD"); - voxel_tc3 = voxel_sh3.getTextureUnit("gbuffer0"); - #if (rp_voxels == "Voxel AO") - voxel_td3 = voxel_sh3.getTextureUnit("voxels_ao"); - #else - voxel_td3 = voxel_sh3.getTextureUnit("voxels_diffuse"); - #end - voxel_te3 = voxel_sh3.getTextureUnit("gbuffer1"); - voxel_tf3 = voxel_sh3.getTextureUnit("gbuffer2"); - #if lnx_brdf - voxel_tg3 = voxel_sh3.getTextureUnit("senvmapBrdf"); - #end - #if lnx_radiance - voxel_th3 = voxel_sh3.getTextureUnit("senvmapRadiance"); - #end - voxel_ca3 = voxel_sh3.getConstantLocation("clipmaps"); - voxel_cb3 = voxel_sh3.getConstantLocation("InvVP"); - voxel_cc3 = voxel_sh3.getConstantLocation("eye"); - voxel_cd3 = voxel_sh3.getConstantLocation("postprocess_resolution"); - voxel_ce3 = voxel_sh3.getConstantLocation("envmapStrength"); - #if lnx_irradiance - voxel_cf3 = voxel_sh3.getConstantLocation("shirr"); - #end - #if lnx_radiance - voxel_cg3 = voxel_sh3.getConstantLocation("envmapNumMipmaps"); - #end - #if lnx_envcol - voxel_ch3 = voxel_sh3.getConstantLocation("backgroundCol"); - #end - } - #if (rp_voxels == "Voxel GI") - if (voxel_sh4 == null) - { - voxel_sh4 = path.getComputeShader("voxel_resolve_specular"); - voxel_ta4 = voxel_sh4.getTextureUnit("voxels"); - voxel_tb4 = voxel_sh4.getTextureUnit("gbufferD"); - voxel_tc4 = voxel_sh4.getTextureUnit("gbuffer0"); - voxel_td4 = voxel_sh4.getTextureUnit("voxelsSDF"); - voxel_te4 = voxel_sh4.getTextureUnit("voxels_specular"); - voxel_tf4 = voxel_sh4.getTextureUnit("sveloc"); - voxel_ca4 = voxel_sh4.getConstantLocation("clipmaps"); - voxel_cb4 = voxel_sh4.getConstantLocation("InvVP"); - voxel_cc4 = voxel_sh4.getConstantLocation("eye"); - voxel_cd4 = voxel_sh4.getConstantLocation("postprocess_resolution"); - } - #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("voxelsOut").image, kha.compute.Access.Read); - kha.compute.Compute.setTexture(voxel_tb0, rts.get("voxelsOutB").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("voxels").image, kha.compute.Access.Read); - kha.compute.Compute.setTexture(voxel_tb1, rts.get("voxelsOutB").image, kha.compute.Access.Read); - kha.compute.Compute.setTexture(voxel_tc1, rts.get("voxelsOut").image, kha.compute.Access.Write); - #if (rp_voxels == "Voxel GI") - kha.compute.Compute.setSampledTexture(voxel_td1, rts.get("voxelsOutB").image); - kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").image, kha.compute.Access.Write); - #else - #if lnx_voxelgi_shadows - kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").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.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8)); - } - - #if (lnx_voxelgi_shadows || (rp_voxels == "Voxel GI")) - 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 = "voxelsSDF"; - var write_sdf = "voxelsSDFtmp"; - - 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 == "voxelsSDF" ? "voxelsSDFtmp" : "voxelsSDF"; - write_sdf = write_sdf == "voxelsSDF" ? "voxelsSDFtmp" : "voxelsSDF"; - } - } - } - #end - - #if (rp_voxels == "Voxel AO") - 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("voxelsOut").image); - kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); - kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image); - kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_ao").image, kha.compute.Access.Write); - - kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image); - #if rp_gbuffer2 - kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image); - #end - #if lnx_brdf - kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png")); - #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()); - } - else { - 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("voxelsOut").image); - kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); - kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image); - kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_diffuse").image, kha.compute.Access.Write); - kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image); - #if rp_gbuffer2 - kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image); - #end - #if lnx_brdf - kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png")); - #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()); - } - else { - 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("voxelsOut").image); - kha.compute.Compute.setSampledTexture(voxel_tb4, rts.get("half").image); - kha.compute.Compute.setSampledTexture(voxel_tc4, rts.get("gbuffer0").image); - kha.compute.Compute.setSampledTexture(voxel_td4, rts.get("voxelsSDF").image); - kha.compute.Compute.setTexture(voxel_te4, rts.get("voxels_specular").image, kha.compute.Access.Write); - #if rp_gbuffer2 - kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").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()); - } - else { - 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 + 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 != 'Off') && lnx_config) + static var voxelsCreated = false; + #end + + #if (rp_voxels != "Off") + 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 == "Voxel GI") + 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 == "Voxel GI") + 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 == "Voxel GI") + 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 == "sun" ? + 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("point", true)) : ShadowMapAtlas.shadowMapAtlases.get(ShadowMapAtlas.shadowMapAtlasName("point", false)); + if (atlas != null) { + if(LightObject.pointLightsData == null) { + LightObject.pointLightsData = new kha.arrays.Float32Array( + LightObject.maxLightsCluster * ShadowMapTile.tilesLightType("point") * 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 == "point") { + 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 ? "RGBA64" : "DEPTH16"; + 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); + } + else 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) { + case "sun": tile.light.setCascade(iron.Scene.active.camera, face); + case "point": path.currentFace = face; + } + #else + path.currentFace = face; + #end + face++; + } + path.setCurrentViewportWithOffset(lTile.size, lTile.size, lTile.coordsX, lTile.coordsY); + + path.drawMeshesStream("shadowmap"); + }); + #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) { + case "sun": tile.light.setCascade(iron.Scene.active.camera, face); + case "point": path.currentFace = face; + } + #else + path.currentFace = face; + #end + face++; + } + path.setCurrentViewportWithOffset(lTile.size, lTile.size, lTile.coordsX, lTile.coordsY); + + path.drawMeshesStream("shadowmap_transparent"); + }); + #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 != "sun") continue; + var n = "shadowMap"; + path.bindTarget(n, n); + var n = "shadowMapTransparent"; + path.bindTarget(n, n); + break; + } + for (i in 0...pointIndex) { + var n = "shadowMapPoint[" + i + "]"; + path.bindTarget(n, n); + var n = "shadowMapPointTransparent[" + i + "]"; + path.bindTarget(n, n); + } + for (i in 0...spotIndex) { + var n = "shadowMapSpot[" + i + "]"; + path.bindTarget(n, n); + var n = "shadowMapSpotTransparent[" + i + "]"; + path.bindTarget(n, n); + } + } + + static function shadowMapName(light: LightObject, transparent: Bool): String { + switch (light.data.raw.type) { + case "sun": + return transparent ? "shadowMapTransparent" : "shadowMap"; + case "point": + return transparent ? "shadowMapPointTransparent[" + pointIndex + "]" : "shadowMapPoint[" + pointIndex + "]"; + default: + return transparent ? "shadowMapSpotTransparent[" + spotIndex + "]" : "shadowMapSpot[" + 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 ? "RGBA64" : "DEPTH16"; + t.is_cubemap = true; + rt = path.createRenderTarget(t); + } + else { // 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 == "sun") { + sizew = sizew * iron.object.LightObject.cascadeCount; + } + #end + var t = new RenderTargetRaw(); + t.name = target; + t.width = sizew; + t.height = sizeh; + t.format = transparent ? "RGBA64" : "DEPTH16"; + 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("shadowmap"); + } + } + path.currentFace = -1; + + if (l.data.raw.type == "point") pointIndex++; + else if (l.data.raw.type == "spot" || l.data.raw.type == "area") 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("shadowmap_transparent"); + } + } + path.currentFace = -1; + + if (l.data.raw.type == "point") pointIndex++; + else if (l.data.raw.type == "spot" || l.data.raw.type == "area") 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 == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) { + l.data.raw.shadowmap_size = config.rp_shadowmap_cascade; + var rt = path.renderTargets.get("shadowMap"); + if (rt != null) { + rt.unload(); + path.renderTargets.remove("shadowMap"); + } + } + else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) { + l.data.raw.shadowmap_size = config.rp_shadowmap_cube; + var rt = path.renderTargets.get("shadowMapCube"); + if (rt != null) { + rt.unload(); + path.renderTargets.remove("shadowMapCube"); + } + } + 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 != 'Off') + if (!voxelsCreated) initGI(); + #end + #end // lnx_config + } + + #if (rp_translucency) + public static function initTranslucency() { + path.createDepthBuffer("main", "DEPTH24"); + + var t = new RenderTargetRaw(); + t.name = "accum"; + t.width = 0; + t.height = 0; + t.displayp = getDisplayp(); + t.format = "RGBA64"; + t.scale = getSuperSampling(); + t.depth_buffer = "main"; + path.createRenderTarget(t); + + var t = new RenderTargetRaw(); + t.name = "revealage"; + t.width = 0; + t.height = 0; + t.displayp = getDisplayp(); + t.format = "R16"; + t.scale = getSuperSampling(); + t.depth_buffer = "main"; + path.createRenderTarget(t); + + path.loadShader("shader_datas/translucent_resolve/translucent_resolve"); + } + + public static function drawTranslucency(target: String) { + path.setTarget("accum"); + path.clearTarget(0xff000000); + path.setTarget("revealage"); + path.clearTarget(0xffffffff); + path.setTarget("accum", ["revealage"]); + + #if rp_shadowmap + { + #if lnx_shadowmap_atlas + bindShadowMapAtlas(); + #else + bindShadowMap(); + #end + } + #end + + #if (rp_voxels != "Off") + path.bindTarget("voxelsOut", "voxels"); + #if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows) + path.bindTarget("voxelsSDF", "voxelsSDF"); + #end + #end + + #if rp_ssrs + path.bindTarget("_main", "gbufferD"); + #end + + path.drawMeshes("translucent"); + + #if rp_render_to_texture + { + path.setTarget(target); + } + #else + { + path.setTarget(""); + } + #end + + path.bindTarget("accum", "gbuffer0"); + path.bindTarget("revealage", "gbuffer1"); + path.drawShader("shader_datas/translucent_resolve/translucent_resolve"); + } + #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 != 'Off') + public static function initGI(tname = "voxels") { + 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 == "voxels_diffuse" || t.name == "voxels_specular" || t.name == "voxels_ao") { + t.width = 0; + t.height = 0; + t.displayp = getDisplayp(); + t.format = "RGBA32"; + } + else { + if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") { + t.format = "R16"; + t.width = res; + t.height = res * Main.voxelgiClipmapCount; + t.depth = res; + } + else { + #if (rp_voxels == "Voxel AO") + { + if (t.name == "voxelsOut" || t.name == "voxelsOutB") { + t.format = "R16"; + t.width = res * (6 + 16); + t.height = res * Main.voxelgiClipmapCount; + t.depth = res; + } + else { + t.format = "R32UI"; + t.width = res * 6; + t.height = res; + t.depth = res * 2; + } + } + #else + { + if (t.name == "voxelsOut" || t.name == "voxelsOutB") { + t.format = "RGBA64"; + t.width = res * (6 + 16); + t.height = res * Main.voxelgiClipmapCount; + t.depth = res; + } + else { + t.format = "R32UI"; + 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 "RGBA64"; + #else + return "RGBA32"; + #end + } + + public static inline function getDisplayp(): Null { + #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 != "Off") + public static function computeVoxelsBegin() { + if (voxel_sh0 == null) + { + voxel_sh0 = path.getComputeShader("voxel_offsetprev"); + + voxel_ta0 = voxel_sh0.getTextureUnit("voxelsB"); + voxel_tb0 = voxel_sh0.getTextureUnit("voxelsOut"); + + voxel_ca0 = voxel_sh0.getConstantLocation("clipmaps"); + voxel_cb0 = voxel_sh0.getConstantLocation("clipmapLevel"); + } + if (voxel_sh1 == null) + { + voxel_sh1 = path.getComputeShader("voxel_temporal"); + voxel_ta1 = voxel_sh1.getTextureUnit("voxels"); + voxel_tb1 = voxel_sh1.getTextureUnit("voxelsB"); + voxel_tc1 = voxel_sh1.getTextureUnit("voxelsOut"); + + voxel_ca1 = voxel_sh1.getConstantLocation("clipmaps"); + voxel_cb1 = voxel_sh1.getConstantLocation("clipmapLevel"); + voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength"); + + #if (rp_voxels == "Voxel GI") + voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler"); + voxel_te1 = voxel_sh1.getTextureUnit("SDF"); + voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength"); + #else + #if lnx_voxelgi_shadows + voxel_te1 = voxel_sh1.getTextureUnit("SDF"); + #end + #end + } + #if (lnx_voxelgi_shadows || rp_voxels == "Voxel GI") + if (voxel_sh2 == null) + { + voxel_sh2 = path.getComputeShader("voxel_sdf_jumpflood"); + voxel_ta2 = voxel_sh2.getTextureUnit("voxelsSDF"); + voxel_tb2 = voxel_sh2.getTextureUnit("voxelsSDFtmp"); + + voxel_ca2 = voxel_sh2.getConstantLocation("clipmaps"); + voxel_cb2 = voxel_sh2.getConstantLocation("clipmapLevel"); + voxel_cc2 = voxel_sh2.getConstantLocation("jump_size"); + } + #end + if (voxel_sh3 == null) + { + #if (rp_voxels == "Voxel AO") + voxel_sh3 = path.getComputeShader("voxel_resolve_ao"); + #else + voxel_sh3 = path.getComputeShader("voxel_resolve_diffuse"); + #end + voxel_ta3 = voxel_sh3.getTextureUnit("voxels"); + voxel_tb3 = voxel_sh3.getTextureUnit("gbufferD"); + voxel_tc3 = voxel_sh3.getTextureUnit("gbuffer0"); + #if (rp_voxels == "Voxel AO") + voxel_td3 = voxel_sh3.getTextureUnit("voxels_ao"); + #else + voxel_td3 = voxel_sh3.getTextureUnit("voxels_diffuse"); + #end + voxel_te3 = voxel_sh3.getTextureUnit("gbuffer1"); + voxel_tf3 = voxel_sh3.getTextureUnit("gbuffer2"); + #if lnx_brdf + voxel_tg3 = voxel_sh3.getTextureUnit("senvmapBrdf"); + #end + #if lnx_radiance + voxel_th3 = voxel_sh3.getTextureUnit("senvmapRadiance"); + #end + voxel_ca3 = voxel_sh3.getConstantLocation("clipmaps"); + voxel_cb3 = voxel_sh3.getConstantLocation("InvVP"); + voxel_cc3 = voxel_sh3.getConstantLocation("eye"); + voxel_cd3 = voxel_sh3.getConstantLocation("postprocess_resolution"); + voxel_ce3 = voxel_sh3.getConstantLocation("envmapStrength"); + #if lnx_irradiance + voxel_cf3 = voxel_sh3.getConstantLocation("shirr"); + #end + #if lnx_radiance + voxel_cg3 = voxel_sh3.getConstantLocation("envmapNumMipmaps"); + #end + #if lnx_envcol + voxel_ch3 = voxel_sh3.getConstantLocation("backgroundCol"); + #end + } + #if (rp_voxels == "Voxel GI") + if (voxel_sh4 == null) + { + voxel_sh4 = path.getComputeShader("voxel_resolve_specular"); + voxel_ta4 = voxel_sh4.getTextureUnit("voxels"); + voxel_tb4 = voxel_sh4.getTextureUnit("gbufferD"); + voxel_tc4 = voxel_sh4.getTextureUnit("gbuffer0"); + voxel_td4 = voxel_sh4.getTextureUnit("voxelsSDF"); + voxel_te4 = voxel_sh4.getTextureUnit("voxels_specular"); + voxel_tf4 = voxel_sh4.getTextureUnit("sveloc"); + voxel_ca4 = voxel_sh4.getConstantLocation("clipmaps"); + voxel_cb4 = voxel_sh4.getConstantLocation("InvVP"); + voxel_cc4 = voxel_sh4.getConstantLocation("eye"); + voxel_cd4 = voxel_sh4.getConstantLocation("postprocess_resolution"); + } + #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("voxelsOut").image, kha.compute.Access.Read); + kha.compute.Compute.setTexture(voxel_tb0, rts.get("voxelsOutB").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("voxels").image, kha.compute.Access.Read); + kha.compute.Compute.setTexture(voxel_tb1, rts.get("voxelsOutB").image, kha.compute.Access.Read); + kha.compute.Compute.setTexture(voxel_tc1, rts.get("voxelsOut").image, kha.compute.Access.Write); + #if (rp_voxels == "Voxel GI") + kha.compute.Compute.setSampledTexture(voxel_td1, rts.get("voxelsOutB").image); + kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").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("voxelsSDF").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 == "Voxel GI")) + 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 = "voxelsSDF"; + var write_sdf = "voxelsSDFtmp"; + + 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 == "voxelsSDF" ? "voxelsSDFtmp" : "voxelsSDF"; + write_sdf = write_sdf == "voxelsSDF" ? "voxelsSDFtmp" : "voxelsSDF"; + } + } + } + #end + + #if (rp_voxels == "Voxel AO") + 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("voxelsOut").image); + kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); + kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image); + kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_ao").image, kha.compute.Access.Write); + + kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image); + #if rp_gbuffer2 + kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image); + #end + #if lnx_brdf + kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png")); + #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()); + } + else { + 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("voxelsOut").image); + kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); + kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image); + kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_diffuse").image, kha.compute.Access.Write); + kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image); + #if rp_gbuffer2 + kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image); + #end + #if lnx_brdf + kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png")); + #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()); + } + else { + 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("voxelsOut").image); + kha.compute.Compute.setSampledTexture(voxel_tb4, rts.get("half").image); + kha.compute.Compute.setSampledTexture(voxel_tc4, rts.get("gbuffer0").image); + kha.compute.Compute.setSampledTexture(voxel_td4, rts.get("voxelsSDF").image); + kha.compute.Compute.setTexture(voxel_te4, rts.get("voxels_specular").image, kha.compute.Access.Write); + #if rp_gbuffer2 + kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").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()); + } + else { + 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 } #if lnx_shadowmap_atlas class ShadowMapAtlas { - public var target: String; - public var baseTileSizeConst: Int; - public var maxAtlasSizeConst: Int; + public var target: String; + public var baseTileSizeConst: Int; + public var maxAtlasSizeConst: Int; - public var sizew: Int; - public var sizeh: Int; + public var sizew: Int; + public var sizeh: Int; - public var currTileOffset = 0; - public var tiles: Array = []; - public var activeTiles: Array = []; - public var depth = 1; - #if lnx_shadowmap_atlas_lod - var tileSizes: Array = []; - var tileSizeFactor: Array = []; - #end - public var updateRenderTarget = false; - public static var shadowMapAtlases:Map = new Map(); // map a shadowmap atlas to their light type - public static var shadowMapAtlasesTransparent:Map = new Map(); // map a shadowmap atlas to their light type + public var currTileOffset = 0; + public var tiles: Array = []; + public var activeTiles: Array = []; + public var depth = 1; + #if lnx_shadowmap_atlas_lod + var tileSizes: Array = []; + var tileSizeFactor: Array = []; + #end + public var updateRenderTarget = false; + public static var shadowMapAtlases:Map = new Map(); // map a shadowmap atlas to their light type + public static var shadowMapAtlasesTransparent:Map = new Map(); // map a shadowmap atlas to their light type - #if lnx_debug - public var lightType: String; - public var rejectedLights: Array = []; - #end + #if lnx_debug + public var lightType: String; + public var rejectedLights: Array = []; + #end - function new(light: LightObject, transparent: Bool) { + function new(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); + 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_shadowmap_atlas_lod + computeTileSizes(maxTileSize, depth); + #end - #if lnx_debug - #if lnx_shadowmap_atlas_single_map - this.lightType = "any"; - #else - this.lightType = light.data.raw.type; - #end - #end + #if lnx_debug + #if lnx_shadowmap_atlas_single_map + this.lightType = "any"; + #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 the light was added succesfully - */ - 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); - else - shadowMapAtlases.set(atlasName, atlas); - } + /** + * 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 the light was added succesfully + */ + 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); + else + 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; - } + // 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; - else - light.lightInAtlas = true; - } + 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; + else + 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; - } + 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 - } + 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 + #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 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 "shadowMapAtlas"; - #else - switch (type) { - case "point": - return transparent ? "shadowMapAtlasPointTransparent" : "shadowMapAtlasPoint"; - case "sun": - return transparent ? "shadowMapAtlasSunTransparent" : "shadowMapAtlasSun"; - default: - return transparent ? "shadowMapAtlasSpotTransparent" : "shadowMapAtlasSpot"; - } - #end - } + public static inline function shadowMapAtlasName(type: String, transparent: Bool): String { + #if lnx_shadowmap_atlas_single_map + return "shadowMapAtlas"; + #else + switch (type) { + case "point": + return transparent ? "shadowMapAtlasPointTransparent" : "shadowMapAtlasPoint"; + case "sun": + return transparent ? "shadowMapAtlasSunTransparent" : "shadowMapAtlasSun"; + default: + return transparent ? "shadowMapAtlasSpotTransparent" : "shadowMapAtlasSpot"; + } + #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 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) { - case "point": { - #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 - } - case "spot": { - #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 - } - case "sun": { - #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 - } - default: { - #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 - } + 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) { + case "point": { + #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 + } + case "spot": { + #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 + } + case "sun": { + #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 + } + default: { + #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); - } + function freeActiveTile(tile: ShadowMapTile) { + activeTiles.remove(tile); + } } class ShadowMapTile { - public var light:Null = null; - public var coordsX:Int; - public var coordsY:Int; - public var size:Int; - public var tiles:Array = []; - public var linkedTile:ShadowMapTile = null; + public var light:Null = null; + public var coordsX:Int; + public var coordsY:Int; + public var size:Int; + public var tiles:Array = []; + 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; + #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 + static var tilePattern = [[0, 0], [1, 0], [0, 1], [1, 1]]; + #end - function new(coordsX: Int, coordsY: Int, size: Int) { - this.coordsX = coordsX; - this.coordsY = coordsY; - this.size = size; - } + function new(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; + 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; - } - else - #end - tileSize = atlas.getTileSize(light.shadowMapScale); + #if lnx_shadowmap_atlas_lod + if (oldTile != null && oldTile.newTileSize != -1) { + // reuse tilesize instead of computing it again + tileSize = oldTile.newTileSize; + oldTile.newTileSize = -1; + } + else + #end + tileSize = atlas.getTileSize(light.shadowMapScale); - if (tileSize == 0) - return null; + if (tileSize == 0) + return null; - var tiles = []; - tiles = findCreateTiles(light, oldTile, atlas, tilesLightType(light.data.raw.type), tileSize); + 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); + // lock new tiles with light + for (tile in tiles) + tile.lockTile(light); - return linkTiles(tiles); - } + return linkTiles(tiles); + } - static inline function linkTiles(tiles: Array): 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 linkTiles(tiles: Array): 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 { - var tilesFound: Array = []; + static inline function findCreateTiles(light: LightObject, oldTile: ShadowMapTile, atlas: ShadowMapAtlas, tilesPerLightType: Int, tileSize: Int): Array { + var tilesFound: Array = []; - while (tilesFound.length < tilesPerLightType) { - findTiles(light, oldTile, atlas.tiles, tileSize, tilesPerLightType, tilesFound); + 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; + 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; - } + 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, size: Int, tilesCount: Int, tilesFound: Array): 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 - else { - 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); - } - } - } - else - #end - findTilesNaive(light, tiles, size, tilesCount, tilesFound); - } + inline static function findTiles(light:LightObject, oldTile: ShadowMapTile, + tiles: Array, size: Int, tilesCount: Int, tilesFound: Array): 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 + else { + 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); + } + } + } + else + #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; - } + #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 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, size: Int, tilesCount: Int, tilesFound: Array): 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; - } - } - else { - // 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; - } - } - } + static function findTilesNaive(light:LightObject, tiles: Array, size: Int, tilesCount: Int, tilesFound: Array): 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; + } + } + else { + // 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, 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; + // create a basic tile and subdivide it if needed + public static function createTiles(tiles:Array, 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--; - } - } + 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 { - var tileSize = Std.int(size / 2); + #if lnx_shadowmap_atlas_lod + static function subDivTile(parent: ShadowMapTile, size: Int, baseCoordsX: Int, baseCoordsY: Int, depth: Int): Array { + var tileSize = Std.int(size / 2); - var tiles = []; + var tiles = []; - for (i in 0...4) { - var coordsX = baseCoordsX + tilePattern[i][0] * tileSize; - var coordsY = baseCoordsY + tilePattern[i][1] * tileSize; + 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; + 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); - } + if (depth > 1) + tile.tiles = subDivTile(tile, tileSize, coordsX, coordsY, depth - 1); + tiles.push(tile); + } - return tiles; - } - #end + return tiles; + } + #end - public static inline function tilesLightType(type: String): Int { - switch (type) { - case "sun": - return LightObject.cascadeCount; - case "point": - return 6; - default: - return 1; - } - } + public static inline function tilesLightType(type: String): Int { + switch (type) { + case "sun": + return LightObject.cascadeCount; + case "point": + return 6; + default: + return 1; + } + } - public function notifyOnLightRemove() { - unlockLight = true; - freeTile(); - } + 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 - } + 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 var unlockLight: Bool = false; + public var notifyOnFree: ShadowMapTile -> Void; - public function freeTile(): Void { - // prevent duplicates - if (light != null && unlockLight) { - light.lightInAtlas = false; - unlockLight = false; - } + 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 + 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; - } - } + 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; - } - } + 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 + #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 } #end