2019-01-11 00:48:33 -08:00
//
// KRLight.cpp
2021-08-16 16:35:36 -07:00
// Kraken Engine
2019-01-11 00:48:33 -08:00
//
2025-08-31 14:11:20 -07:00
// Copyright 2025 Kearwood Gilbert. All rights reserved.
2021-08-16 16:35:36 -07:00
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
2019-01-11 00:48:33 -08:00
//
# include "KREngine-common.h"
# include "KRLight.h"
# include "KRNode.h"
# include "KRCamera.h"
# include "KRContext.h"
2019-12-01 15:49:49 -08:00
# include "KRPipelineManager.h"
# include "KRPipeline.h"
2019-01-11 00:48:33 -08:00
# include "KRDirectionalLight.h"
# include "KRSpotLight.h"
# include "KRPointLight.h"
2024-01-21 18:34:36 -08:00
# include "KRRenderPass.h"
2019-01-11 00:48:33 -08:00
2023-08-05 21:14:53 -07:00
using namespace hydra ;
2020-06-21 22:42:10 -07:00
/* static */
void KRLight : : InitNodeInfo ( KrNodeInfo * nodeInfo )
{
KRNode : : InitNodeInfo ( nodeInfo ) ;
nodeInfo - > light . casts_shadow = true ;
nodeInfo - > light . color = Vector3 : : One ( ) ;
nodeInfo - > light . decay_start = 0.0f ;
nodeInfo - > light . dust_particle_density = 0.1f ;
nodeInfo - > light . dust_particle_intensity = 1.0f ;
nodeInfo - > light . dust_particle_size = 1.0f ;
nodeInfo - > light . flare_occlusion_size = 0.05f ;
nodeInfo - > light . flare_size = 0.0f ;
nodeInfo - > light . flare_texture = - 1 ;
nodeInfo - > light . intensity = 1.0f ;
nodeInfo - > light . light_shafts = true ;
}
2019-01-11 00:48:33 -08:00
2025-11-17 00:55:50 -08:00
KRLight : : KRLight ( KRScene & scene , std : : string name )
: KRNode ( scene , name )
, m_flareTexture ( KRTextureBinding ( KRTexture : : TEXTURE_USAGE_LIGHT_FLARE ) )
2019-01-11 00:48:33 -08:00
{
2022-08-08 01:07:26 -07:00
m_intensity = 1.0f ;
m_dust_particle_intensity = 1.0f ;
m_color = Vector3 : : One ( ) ;
m_flareSize = 0.0f ;
m_flareOcclusionSize = 0.05f ;
m_casts_shadow = true ;
m_light_shafts = true ;
m_dust_particle_density = 0.1f ;
m_dust_particle_size = 1.0f ;
m_dust_particle_intensity = 1.0f ;
m_occlusionQuery = 0 ;
m_decayStart = 0 ;
// Initialize shadow buffers
m_cShadowBuffers = 0 ;
for ( int iBuffer = 0 ; iBuffer < KRENGINE_MAX_SHADOW_BUFFERS ; iBuffer + + ) {
shadowFramebuffer [ iBuffer ] = 0 ;
shadowDepthTexture [ iBuffer ] = 0 ;
shadowValid [ iBuffer ] = false ;
}
2019-01-11 00:48:33 -08:00
}
KRLight : : ~ KRLight ( )
{
2022-08-08 01:07:26 -07:00
if ( m_occlusionQuery ) {
GLDEBUG ( glDeleteQueriesEXT ( 1 , & m_occlusionQuery ) ) ;
m_occlusionQuery = 0 ;
}
allocateShadowBuffers ( 0 ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
tinyxml2 : : XMLElement * KRLight : : saveXML ( tinyxml2 : : XMLNode * parent )
2019-01-11 00:48:33 -08:00
{
2022-08-08 01:07:26 -07:00
tinyxml2 : : XMLElement * e = KRNode : : saveXML ( parent ) ;
e - > SetAttribute ( " intensity " , m_intensity ) ;
e - > SetAttribute ( " color_r " , m_color . x ) ;
e - > SetAttribute ( " color_g " , m_color . y ) ;
e - > SetAttribute ( " color_b " , m_color . z ) ;
e - > SetAttribute ( " decay_start " , m_decayStart ) ;
e - > SetAttribute ( " flare_size " , m_flareSize ) ;
e - > SetAttribute ( " flare_occlusion_size " , m_flareOcclusionSize ) ;
2025-11-11 14:21:34 -08:00
e - > SetAttribute ( " flare_texture " , m_flareTexture . getName ( ) . c_str ( ) ) ;
2022-08-08 01:07:26 -07:00
e - > SetAttribute ( " casts_shadow " , m_casts_shadow ? " true " : " false " ) ;
e - > SetAttribute ( " light_shafts " , m_light_shafts ? " true " : " false " ) ;
e - > SetAttribute ( " dust_particle_density " , m_dust_particle_density ) ;
e - > SetAttribute ( " dust_particle_size " , m_dust_particle_size ) ;
e - > SetAttribute ( " dust_particle_intensity " , m_dust_particle_intensity ) ;
return e ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : loadXML ( tinyxml2 : : XMLElement * e )
{
KRNode : : loadXML ( e ) ;
float x = 1.0f , y = 1.0f , z = 1.0f ;
if ( e - > QueryFloatAttribute ( " color_r " , & x ) ! = tinyxml2 : : XML_SUCCESS ) {
x = 1.0 ;
}
if ( e - > QueryFloatAttribute ( " color_g " , & y ) ! = tinyxml2 : : XML_SUCCESS ) {
y = 1.0 ;
}
if ( e - > QueryFloatAttribute ( " color_b " , & z ) ! = tinyxml2 : : XML_SUCCESS ) {
z = 1.0 ;
}
m_color = Vector3 : : Create ( x , y , z ) ;
if ( e - > QueryFloatAttribute ( " intensity " , & m_intensity ) ! = tinyxml2 : : XML_SUCCESS ) {
m_intensity = 100.0 ;
}
if ( e - > QueryFloatAttribute ( " decay_start " , & m_decayStart ) ! = tinyxml2 : : XML_SUCCESS ) {
m_decayStart = 0.0 ;
}
if ( e - > QueryFloatAttribute ( " flare_size " , & m_flareSize ) ! = tinyxml2 : : XML_SUCCESS ) {
m_flareSize = 0.0 ;
}
if ( e - > QueryFloatAttribute ( " flare_occlusion_size " , & m_flareOcclusionSize ) ! = tinyxml2 : : XML_SUCCESS ) {
m_flareOcclusionSize = 0.05f ;
}
if ( e - > QueryBoolAttribute ( " casts_shadow " , & m_casts_shadow ) ! = tinyxml2 : : XML_SUCCESS ) {
m_casts_shadow = true ;
}
if ( e - > QueryBoolAttribute ( " light_shafts " , & m_light_shafts ) ! = tinyxml2 : : XML_SUCCESS ) {
m_light_shafts = true ;
}
m_dust_particle_density = 0.1f ;
if ( e - > QueryFloatAttribute ( " dust_particle_density " , & m_dust_particle_density ) ! = tinyxml2 : : XML_SUCCESS ) {
2019-01-11 00:48:33 -08:00
m_dust_particle_density = 0.1f ;
2022-08-08 01:07:26 -07:00
}
m_dust_particle_size = 1.0f ;
if ( e - > QueryFloatAttribute ( " dust_particle_size " , & m_dust_particle_size ) ! = tinyxml2 : : XML_SUCCESS ) {
2019-01-11 00:48:33 -08:00
m_dust_particle_size = 1.0f ;
2022-08-08 01:07:26 -07:00
}
m_dust_particle_intensity = 1.0f ;
if ( e - > QueryFloatAttribute ( " dust_particle_intensity " , & m_dust_particle_intensity ) ! = tinyxml2 : : XML_SUCCESS ) {
2019-01-11 00:48:33 -08:00
m_dust_particle_intensity = 1.0f ;
2022-08-08 01:07:26 -07:00
}
const char * szFlareTexture = e - > Attribute ( " flare_texture " ) ;
if ( szFlareTexture ) {
2025-11-13 22:31:00 -08:00
m_flareTexture . set ( szFlareTexture ) ;
2022-08-08 01:07:26 -07:00
} else {
2025-11-11 14:21:34 -08:00
m_flareTexture . clear ( ) ;
2022-08-08 01:07:26 -07:00
}
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setFlareTexture ( std : : string flare_texture )
{
2025-11-13 22:31:00 -08:00
m_flareTexture . set ( flare_texture ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setFlareSize ( float flare_size )
{
m_flareSize = flare_size ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setFlareOcclusionSize ( float occlusion_size )
{
m_flareOcclusionSize = occlusion_size ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setIntensity ( float intensity )
{
m_intensity = intensity ;
2019-01-11 00:48:33 -08:00
}
2025-08-31 16:17:21 -07:00
float KRLight : : getIntensity ( ) const
2022-08-08 01:07:26 -07:00
{
return m_intensity ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
const Vector3 & KRLight : : getColor ( )
{
return m_color ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setColor ( const Vector3 & color )
{
m_color = color ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : setDecayStart ( float decayStart )
{
m_decayStart = decayStart ;
2019-01-11 00:48:33 -08:00
}
2025-08-31 16:17:21 -07:00
float KRLight : : getDecayStart ( ) const
2022-08-08 01:07:26 -07:00
{
return m_decayStart ;
2019-01-11 00:48:33 -08:00
}
2025-11-17 19:40:51 -08:00
void KRLight : : getResourceBindings ( std : : list < KRResourceBinding * > & bindings )
2025-11-14 23:55:44 -08:00
{
2025-11-17 19:40:51 -08:00
KRNode : : getResourceBindings ( bindings ) ;
2025-11-14 23:55:44 -08:00
2025-11-17 19:40:51 -08:00
bindings . push_back ( & m_flareTexture ) ;
2025-11-14 23:55:44 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : render ( RenderInfo & ri )
{
KRNode : : render ( ri ) ;
2024-01-22 00:35:49 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_SHADOWMAP & & ( ri . camera - > settings . volumetric_environment_enable | | ri . camera - > settings . dust_particle_enable | | ( ri . camera - > settings . m_cShadowBuffers > 0 & & m_casts_shadow ) ) ) {
2024-09-21 16:46:04 -07:00
allocateShadowBuffers ( configureShadowBufferViewports ( * ri . viewport ) ) ;
2022-08-08 01:07:26 -07:00
renderShadowBuffers ( ri ) ;
}
2024-01-21 18:34:36 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_ADDITIVE_PARTICLES & & ri . camera - > settings . dust_particle_enable ) {
2022-08-08 01:07:26 -07:00
// Render brownian particles for dust floating in air
if ( m_cShadowBuffers > = 1 & & shadowValid [ 0 ] & & m_dust_particle_density > 0.0f & & m_dust_particle_size > 0.0f & & m_dust_particle_intensity > 0.0f ) {
2024-09-21 16:46:04 -07:00
if ( ri . viewport - > visible ( getBounds ( ) ) | | true ) { // FINDME, HACK need to remove "|| true"?
2022-08-08 01:07:26 -07:00
float particle_range = 600.0f ;
int particle_count = ( int ) ( m_dust_particle_density * pow ( particle_range , 3 ) ) ;
if ( particle_count > KRMeshManager : : KRENGINE_MAX_RANDOM_PARTICLES ) {
particle_count = KRMeshManager : : KRENGINE_MAX_RANDOM_PARTICLES ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
Matrix4 particleModelMatrix ;
particleModelMatrix . scale ( particle_range ) ; // Scale the box symetrically to ensure that we don't have an uneven distribution of particles for different angles of the view frustrum
2024-09-21 16:46:04 -07:00
particleModelMatrix . translate ( ri . viewport - > getCameraPosition ( ) ) ;
2022-08-08 01:07:26 -07:00
std : : vector < KRDirectionalLight * > this_directional_light ;
std : : vector < KRSpotLight * > this_spot_light ;
std : : vector < KRPointLight * > this_point_light ;
KRDirectionalLight * directional_light = dynamic_cast < KRDirectionalLight * > ( this ) ;
KRSpotLight * spot_light = dynamic_cast < KRSpotLight * > ( this ) ;
KRPointLight * point_light = dynamic_cast < KRPointLight * > ( this ) ;
if ( directional_light ) {
this_directional_light . push_back ( directional_light ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
if ( spot_light ) {
this_spot_light . push_back ( spot_light ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
if ( point_light ) {
this_point_light . push_back ( point_light ) ;
2019-01-11 00:48:33 -08:00
}
2022-04-04 02:00:01 -07:00
2022-04-14 00:48:03 -07:00
PipelineInfo info { } ;
2022-08-08 01:07:26 -07:00
std : : string shader_name ( " dust_particle " ) ;
2022-04-04 02:00:01 -07:00
info . shader_name = & shader_name ;
2022-04-06 01:00:13 -07:00
info . pCamera = ri . camera ;
2022-04-04 02:00:01 -07:00
info . point_lights = & this_point_light ;
info . directional_lights = & this_directional_light ;
info . spot_lights = & this_spot_light ;
2022-08-08 01:07:26 -07:00
info . renderPass = ri . renderPass ;
2022-07-07 22:51:16 -07:00
info . rasterMode = RasterMode : : kAdditive ;
info . cullMode = CullMode : : kCullNone ;
2022-08-08 01:07:26 -07:00
info . vertexAttributes = ( 1 < < KRMesh : : KRENGINE_ATTRIB_VERTEX ) | ( 1 < < KRMesh : : KRENGINE_ATTRIB_TEXUVA ) ;
2022-07-07 22:51:16 -07:00
info . modelFormat = ModelFormat : : KRENGINE_MODEL_FORMAT_TRIANGLES ;
2022-08-08 01:07:26 -07:00
KRPipeline * pParticleShader = m_pContext - > getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
2025-08-31 16:17:21 -07:00
pParticleShader - > setPushConstant ( ShaderValue : : dust_particle_color , m_color * ri . camera - > settings . dust_particle_intensity * m_dust_particle_intensity * m_intensity ) ;
2025-08-23 14:59:08 -07:00
pParticleShader - > setPushConstant ( ShaderValue : : particle_origin , Matrix4 : : DotWDiv ( Matrix4 : : Invert ( particleModelMatrix ) , Vector3 : : Zero ( ) ) ) ;
2024-09-21 17:16:13 -07:00
pParticleShader - > bind ( ri , particleModelMatrix ) ; // TODO: Pass light index to shader
2022-08-08 01:07:26 -07:00
m_pContext - > getMeshManager ( ) - > bindVBO ( ri . commandBuffer , & m_pContext - > getMeshManager ( ) - > KRENGINE_VBO_DATA_RANDOM_PARTICLES , 1.0f ) ;
vkCmdDraw ( ri . commandBuffer , particle_count * 3 , 1 , 0 , 0 ) ;
}
}
}
2019-01-11 00:48:33 -08:00
2022-08-08 01:07:26 -07:00
2024-01-21 18:34:36 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE & & ri . camera - > settings . volumetric_environment_enable & & m_light_shafts ) {
2022-08-08 01:07:26 -07:00
std : : string shader_name = ri . camera - > settings . volumetric_environment_downsample ! = 0 ? " volumetric_fog_downsampled " : " volumetric_fog " ;
std : : vector < KRDirectionalLight * > this_directional_light ;
std : : vector < KRSpotLight * > this_spot_light ;
std : : vector < KRPointLight * > this_point_light ;
KRDirectionalLight * directional_light = dynamic_cast < KRDirectionalLight * > ( this ) ;
KRSpotLight * spot_light = dynamic_cast < KRSpotLight * > ( this ) ;
KRPointLight * point_light = dynamic_cast < KRPointLight * > ( this ) ;
if ( directional_light ) {
this_directional_light . push_back ( directional_light ) ;
}
if ( spot_light ) {
this_spot_light . push_back ( spot_light ) ;
}
if ( point_light ) {
this_point_light . push_back ( point_light ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
PipelineInfo info { } ;
info . shader_name = & shader_name ;
info . pCamera = ri . camera ;
info . point_lights = & this_point_light ;
info . directional_lights = & this_directional_light ;
info . spot_lights = & this_spot_light ;
2024-01-21 18:34:36 -08:00
info . renderPass = ri . renderPass ;
2022-08-08 01:07:26 -07:00
info . rasterMode = RasterMode : : kAdditive ;
info . cullMode = CullMode : : kCullNone ;
info . vertexAttributes = ( 1 < < KRMesh : : KRENGINE_ATTRIB_VERTEX ) ;
info . modelFormat = ModelFormat : : KRENGINE_MODEL_FORMAT_TRIANGLES ;
KRPipeline * pFogShader = m_pContext - > getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
int slice_count = ( int ) ( ri . camera - > settings . volumetric_environment_quality * 495.0 ) + 5 ;
float slice_near = - ri . camera - > settings . getPerspectiveNearZ ( ) ;
float slice_far = - ri . camera - > settings . volumetric_environment_max_distance ;
float slice_spacing = ( slice_far - slice_near ) / slice_count ;
2025-08-23 14:59:08 -07:00
pFogShader - > setPushConstant ( ShaderValue : : slice_depth_scale , Vector2 : : Create ( slice_near , slice_spacing ) ) ;
pFogShader - > setPushConstant ( ShaderValue : : light_color , ( m_color * ri . camera - > settings . volumetric_environment_intensity * m_intensity * - slice_spacing / 1000.0f ) ) ;
2024-09-21 17:16:13 -07:00
pFogShader - > bind ( ri , Matrix4 ( ) ) ; // TODO: Pass indexes of lights to shader
2022-08-08 01:07:26 -07:00
m_pContext - > getMeshManager ( ) - > bindVBO ( ri . commandBuffer , & m_pContext - > getMeshManager ( ) - > KRENGINE_VBO_DATA_VOLUMETRIC_LIGHTING , 1.0f ) ;
vkCmdDraw ( ri . commandBuffer , slice_count * 6 , 1 , 0 , 0 ) ;
}
2024-01-21 18:34:36 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_PARTICLE_OCCLUSION ) {
2025-11-14 23:55:44 -08:00
if ( m_flareTexture . isBound ( ) & & m_flareSize > 0.0f ) {
2025-11-11 23:07:04 -08:00
KRMesh * sphereModel = getContext ( ) . getMeshManager ( ) - > getMesh ( " __sphere " ) ;
2022-08-08 01:07:26 -07:00
if ( sphereModel ) {
Matrix4 occlusion_test_sphere_matrix = Matrix4 ( ) ;
occlusion_test_sphere_matrix . scale ( m_localScale * m_flareOcclusionSize ) ;
occlusion_test_sphere_matrix . translate ( m_localTranslation ) ;
if ( m_parentNode ) {
occlusion_test_sphere_matrix * = m_parentNode - > getModelMatrix ( ) ;
}
PipelineInfo info { } ;
std : : string shader_name ( " occlusion_test " ) ;
info . shader_name = & shader_name ;
info . pCamera = ri . camera ;
info . point_lights = & ri . point_lights ;
info . directional_lights = & ri . directional_lights ;
info . spot_lights = & ri . spot_lights ;
info . renderPass = ri . renderPass ;
info . rasterMode = RasterMode : : kAdditive ;
info . cullMode = CullMode : : kCullNone ;
info . modelFormat = sphereModel - > getModelFormat ( ) ;
info . vertexAttributes = sphereModel - > getVertexAttributes ( ) ;
KRPipeline * pPipeline = getContext ( ) . getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
2024-09-21 17:16:13 -07:00
pPipeline - > bind ( ri , occlusion_test_sphere_matrix ) ;
2022-08-08 01:07:26 -07:00
GLDEBUG ( glGenQueriesEXT ( 1 , & m_occlusionQuery ) ) ;
2019-01-11 00:48:33 -08:00
# if TARGET_OS_IPHONE || defined(ANDROID)
2022-08-08 01:07:26 -07:00
GLDEBUG ( glBeginQueryEXT ( GL_ANY_SAMPLES_PASSED_EXT , m_occlusionQuery ) ) ;
2019-01-11 00:48:33 -08:00
# else
2022-08-08 01:07:26 -07:00
GLDEBUG ( glBeginQuery ( GL_SAMPLES_PASSED , m_occlusionQuery ) ) ;
2019-01-11 00:48:33 -08:00
# endif
2022-08-08 01:07:26 -07:00
sphereModel - > renderNoMaterials ( ri . commandBuffer , ri . renderPass , getName ( ) , " occlusion_test " , 1.0f ) ;
# if TARGET_OS_IPHONE || defined(ANDROID)
GLDEBUG ( glEndQueryEXT ( GL_ANY_SAMPLES_PASSED_EXT ) ) ;
# else
GLDEBUG ( glEndQuery ( GL_SAMPLES_PASSED ) ) ;
# endif
}
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
2024-01-21 18:34:36 -08:00
if ( ri . renderPass - > getType ( ) = = RenderPassType : : RENDER_PASS_ADDITIVE_PARTICLES ) {
2025-11-14 23:55:44 -08:00
if ( m_flareTexture . isBound ( ) & & m_flareSize > 0.0f ) {
2022-08-08 01:07:26 -07:00
if ( m_occlusionQuery ) {
2022-09-21 17:59:23 -07:00
int params = 0 ;
2022-08-08 01:07:26 -07:00
GLDEBUG ( glGetQueryObjectuivEXT ( m_occlusionQuery , GL_QUERY_RESULT_EXT , & params ) ) ;
GLDEBUG ( glDeleteQueriesEXT ( 1 , & m_occlusionQuery ) ) ;
if ( params ) {
KRMeshManager : : KRVBOData & vertices = getContext ( ) . getMeshManager ( ) - > KRENGINE_VBO_DATA_2D_SQUARE_VERTICES ;
// Render light flare on transparency pass
PipelineInfo info { } ;
std : : string shader_name ( " flare " ) ;
info . shader_name = & shader_name ;
info . pCamera = ri . camera ;
info . point_lights = & ri . point_lights ;
info . directional_lights = & ri . directional_lights ;
info . spot_lights = & ri . spot_lights ;
info . renderPass = ri . renderPass ;
info . rasterMode = RasterMode : : kAdditiveNoTest ;
info . cullMode = CullMode : : kCullNone ;
info . vertexAttributes = vertices . getVertexAttributes ( ) ;
info . modelFormat = ModelFormat : : KRENGINE_MODEL_FORMAT_STRIP ;
KRPipeline * pShader = getContext ( ) . getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
2025-08-23 14:59:08 -07:00
pShader - > setPushConstant ( ShaderValue : : material_alpha , 1.0f ) ;
2025-11-11 14:21:34 -08:00
pShader - > setImageBinding ( " diffuseTexture " , m_flareTexture . get ( ) , getContext ( ) . getSamplerManager ( ) - > DEFAULT_CLAMPED_SAMPLER ) ;
2024-09-21 17:16:13 -07:00
pShader - > bind ( ri , getModelMatrix ( ) ) ;
2022-08-08 01:07:26 -07:00
m_pContext - > getMeshManager ( ) - > bindVBO ( ri . commandBuffer , & vertices , 1.0f ) ;
vkCmdDraw ( ri . commandBuffer , 4 , 1 , 0 , 0 ) ;
}
}
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
void KRLight : : allocateShadowBuffers ( int cBuffers )
{
// First deallocate buffers no longer needed
for ( int iShadow = cBuffers ; iShadow < KRENGINE_MAX_SHADOW_BUFFERS ; iShadow + + ) {
if ( shadowDepthTexture [ iShadow ] ) {
GLDEBUG ( glDeleteTextures ( 1 , shadowDepthTexture + iShadow ) ) ;
shadowDepthTexture [ iShadow ] = 0 ;
}
if ( shadowFramebuffer [ iShadow ] ) {
GLDEBUG ( glDeleteFramebuffers ( 1 , shadowFramebuffer + iShadow ) ) ;
shadowFramebuffer [ iShadow ] = 0 ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
// Allocate newly required buffers
for ( int iShadow = 0 ; iShadow < cBuffers ; iShadow + + ) {
Vector2 viewportSize = m_shadowViewports [ iShadow ] . getSize ( ) ;
if ( ! shadowDepthTexture [ iShadow ] ) {
shadowValid [ iShadow ] = false ;
GLDEBUG ( glGenFramebuffers ( 1 , shadowFramebuffer + iShadow ) ) ;
GLDEBUG ( glGenTextures ( 1 , shadowDepthTexture + iShadow ) ) ;
// ===== Create offscreen shadow framebuffer object =====
GLDEBUG ( glBindFramebuffer ( GL_FRAMEBUFFER , shadowFramebuffer [ iShadow ] ) ) ;
// ----- Create Depth Texture for shadowFramebuffer -----
2022-09-19 00:14:42 -07:00
// TODO - Vulkan Refactoring. Note: shadowDepthTexture Sampler needs clamp-to-edge and linear filtering
2022-08-08 01:07:26 -07:00
GLDEBUG ( glBindTexture ( GL_TEXTURE_2D , shadowDepthTexture [ iShadow ] ) ) ;
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ) ;
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ) ;
2022-09-19 00:14:42 -07:00
// m_pContext->getTextureManager()->_setWrapModeS(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
// m_pContext->getTextureManager()->_setWrapModeT(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
2019-01-11 00:48:33 -08:00
# if GL_EXT_shadow_samplers
2022-08-08 01:07:26 -07:00
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_MODE_EXT , GL_COMPARE_REF_TO_TEXTURE_EXT ) ) ; // TODO - Detect GL_EXT_shadow_samplers and only activate if available
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_COMPARE_FUNC_EXT , GL_LEQUAL ) ) ; // TODO - Detect GL_EXT_shadow_samplers and only activate if available
2019-01-11 00:48:33 -08:00
# endif
2022-09-21 18:18:13 -07:00
GLDEBUG ( glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT , ( int ) viewportSize . x , ( int ) viewportSize . y , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , NULL ) ) ;
2022-08-08 01:07:26 -07:00
GLDEBUG ( glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , shadowDepthTexture [ iShadow ] , 0 ) ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
m_cShadowBuffers = cBuffers ;
2019-01-11 00:48:33 -08:00
}
void KRLight : : deleteBuffers ( )
{
2022-08-08 01:07:26 -07:00
// Called when this light wasn't used in the last frame, so we can free the resources for use by other lights
allocateShadowBuffers ( 0 ) ;
2019-01-11 00:48:33 -08:00
}
void KRLight : : invalidateShadowBuffers ( )
{
2022-08-08 01:07:26 -07:00
for ( int iShadow = 0 ; iShadow < m_cShadowBuffers ; iShadow + + ) {
shadowValid [ iShadow ] = false ;
}
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
int KRLight : : configureShadowBufferViewports ( const KRViewport & viewport )
2019-01-11 00:48:33 -08:00
{
2022-08-08 01:07:26 -07:00
return 0 ;
2019-01-11 00:48:33 -08:00
}
2022-04-06 01:00:13 -07:00
void KRLight : : renderShadowBuffers ( RenderInfo & ri )
2019-01-11 00:48:33 -08:00
{
2024-09-21 16:46:04 -07:00
KRViewport * prevViewport = ri . viewport ;
2022-08-08 01:07:26 -07:00
for ( int iShadow = 0 ; iShadow < m_cShadowBuffers ; iShadow + + ) {
if ( ! shadowValid [ iShadow ] ) {
shadowValid [ iShadow ] = true ;
GLDEBUG ( glBindFramebuffer ( GL_FRAMEBUFFER , shadowFramebuffer [ iShadow ] ) ) ;
GLDEBUG ( glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , shadowDepthTexture [ iShadow ] , 0 ) ) ;
2022-09-21 18:18:13 -07:00
GLDEBUG ( glViewport ( 0 , 0 , ( int ) m_shadowViewports [ iShadow ] . getSize ( ) . x , ( int ) m_shadowViewports [ iShadow ] . getSize ( ) . y ) ) ;
2022-08-08 01:07:26 -07:00
GLDEBUG ( glClearDepthf ( 0.0f ) ) ;
GLDEBUG ( glClear ( GL_DEPTH_BUFFER_BIT ) ) ;
2022-09-21 18:18:13 -07:00
GLDEBUG ( glViewport ( 1 , 1 , ( int ) m_shadowViewports [ iShadow ] . getSize ( ) . x - 2 , ( int ) m_shadowViewports [ iShadow ] . getSize ( ) . y - 2 ) ) ;
2022-08-08 01:07:26 -07:00
GLDEBUG ( glClearDepthf ( 1.0f ) ) ;
GLDEBUG ( glClear ( GL_DEPTH_BUFFER_BIT ) ) ;
GLDEBUG ( glDisable ( GL_DITHER ) ) ;
// Use shader program
PipelineInfo info { } ;
std : : string shader_name ( " ShadowShader " ) ;
info . shader_name = & shader_name ;
info . pCamera = ri . camera ;
2024-01-21 18:34:36 -08:00
info . renderPass = ri . renderPass ;
2022-08-08 01:07:26 -07:00
info . rasterMode = RasterMode : : kOpaqueLessTest ; // TODO - This is sub-optimal. Evaluate increasing depth buffer resolution instead of disabling depth test.
info . cullMode = CullMode : : kCullNone ; // Disabling culling, which eliminates some self-cast shadow artifacts
KRPipeline * shadowShader = m_pContext - > getPipelineManager ( ) - > getPipeline ( * ri . surface , info ) ;
2024-09-21 16:46:04 -07:00
ri . viewport = & m_shadowViewports [ iShadow ] ;
2024-09-21 17:16:13 -07:00
shadowShader - > bind ( ri , Matrix4 ( ) ) ;
2022-08-08 01:07:26 -07:00
2024-09-21 21:21:48 -07:00
m_shadowViewports [ iShadow ] . expireOcclusionResults ( m_pContext - > getCurrentFrame ( ) ) ;
getScene ( ) . render ( ri ) ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
2024-09-21 16:46:04 -07:00
ri . viewport = prevViewport ;
2019-01-11 00:48:33 -08:00
}
int KRLight : : getShadowBufferCount ( )
{
2022-08-08 01:07:26 -07:00
int cBuffers = 0 ;
for ( int iBuffer = 0 ; iBuffer < m_cShadowBuffers ; iBuffer + + ) {
if ( shadowValid [ iBuffer ] ) {
cBuffers + + ;
} else {
break ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
}
return cBuffers ;
2019-01-11 00:48:33 -08:00
}
2022-09-21 17:59:23 -07:00
int * KRLight : : getShadowTextures ( )
2019-01-11 00:48:33 -08:00
{
2022-08-08 01:07:26 -07:00
return shadowDepthTexture ;
2019-01-11 00:48:33 -08:00
}
2022-08-08 01:07:26 -07:00
KRViewport * KRLight : : getShadowViewports ( )
2019-01-11 00:48:33 -08:00
{
2022-08-08 01:07:26 -07:00
return m_shadowViewports ;
2019-01-11 00:48:33 -08:00
}
2025-08-31 16:17:21 -07:00
bool KRLight : : getShaderValue ( ShaderValue value , float * output ) const
{
switch ( value ) {
case ShaderValue : : light_intensity :
* output = m_intensity * 0.01f ;
return true ;
case ShaderValue : : light_decay_start :
* output = getDecayStart ( ) ;
return true ;
case ShaderValue : : light_cutoff :
* output = KRLIGHT_MIN_INFLUENCE ;
return true ;
case ShaderValue : : flare_size :
* output = m_flareSize ;
return true ;
case ShaderValue : : dust_particle_size :
* output = m_dust_particle_size ;
return true ;
}
return KRNode : : getShaderValue ( value , output ) ;
}
bool KRLight : : getShaderValue ( ShaderValue value , hydra : : Vector3 * output ) const
{
switch ( value ) {
case ShaderValue : : light_position :
* output = m_localTranslation ;
return true ;
case ShaderValue : : light_color :
* output = m_color ;
return true ;
}
return KRNode : : getShaderValue ( value , output ) ;
}