2012-04-05 23:09:41 +00:00
//
// KRLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
# include <iostream>
2012-06-15 00:05:56 +00:00
2012-04-05 23:09:41 +00:00
# import "KRLight.h"
2012-06-15 00:05:56 +00:00
# import "KRNode.h"
# import "KRMat4.h"
# import "KRVector3.h"
# import "KRCamera.h"
# import "KRContext.h"
# import "KRShaderManager.h"
# import "KRShader.h"
2012-09-19 20:26:30 +00:00
# import "KRStockGeometry.h"
2012-09-13 20:09:19 +00:00
# import "assert.h"
2012-06-15 00:05:56 +00:00
2012-08-29 21:43:11 +00:00
KRLight : : KRLight ( KRScene & scene , std : : string name ) : KRNode ( scene , name )
2012-04-05 23:09:41 +00:00
{
2012-04-12 00:43:53 +00:00
m_intensity = 1.0f ;
2012-06-15 00:05:56 +00:00
m_flareTexture = " " ;
m_pFlareTexture = NULL ;
m_flareSize = 0.0 ;
2012-11-16 02:58:23 +00:00
m_casts_shadow = true ;
m_light_shafts = true ;
2012-11-15 22:05:25 +00:00
// Initialize shadow buffers
m_cShadowBuffers = 0 ;
2012-11-16 02:58:23 +00:00
for ( int iBuffer = 0 ; iBuffer < KRENGINE_MAX_SHADOW_BUFFERS ; iBuffer + + ) {
shadowFramebuffer [ iBuffer ] = 0 ;
shadowDepthTexture [ iBuffer ] = 0 ;
shadowValid [ iBuffer ] = false ;
}
2012-04-05 23:09:41 +00:00
}
KRLight : : ~ KRLight ( )
{
2012-11-15 22:05:25 +00:00
allocateShadowBuffers ( 0 ) ;
2012-04-05 23:09:41 +00:00
}
2012-04-12 00:43:53 +00:00
tinyxml2 : : XMLElement * KRLight : : saveXML ( tinyxml2 : : XMLNode * parent )
2012-04-05 23:09:41 +00:00
{
2012-04-12 00:43:53 +00: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 ) ;
2012-06-15 00:05:56 +00:00
e - > SetAttribute ( " flare_size " , m_flareSize ) ;
e - > SetAttribute ( " flare_texture " , m_flareTexture . c_str ( ) ) ;
2012-11-16 02:58:23 +00:00
e - > SetAttribute ( " casts_shadow " , m_casts_shadow ? " true " : " false " ) ;
e - > SetAttribute ( " light_shafts " , m_light_shafts ? " true " : " false " ) ;
2012-04-12 00:43:53 +00:00
return e ;
}
2012-04-12 01:27:30 +00:00
void KRLight : : loadXML ( tinyxml2 : : XMLElement * e ) {
KRNode : : loadXML ( e ) ;
float x , y , z ;
2012-06-15 00:05:56 +00:00
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 ;
}
2012-04-12 01:27:30 +00:00
m_color = KRVector3 ( x , y , z ) ;
2012-06-15 00:05:56 +00:00
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 ;
}
2012-11-16 02:58:23 +00:00
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 ;
}
2012-06-15 00:05:56 +00:00
const char * szFlareTexture = e - > Attribute ( " flare_texture " ) ;
if ( szFlareTexture ) {
m_flareTexture = szFlareTexture ;
} else {
m_flareTexture = " " ;
}
m_pFlareTexture = NULL ;
}
void KRLight : : setFlareTexture ( std : : string flare_texture ) {
m_flareTexture = flare_texture ;
m_pFlareTexture = NULL ;
}
void KRLight : : setFlareSize ( float flare_size ) {
m_flareSize = flare_size ;
2012-04-12 01:27:30 +00:00
}
2012-04-12 00:43:53 +00:00
void KRLight : : setIntensity ( float intensity ) {
m_intensity = intensity ;
}
float KRLight : : getIntensity ( ) {
return m_intensity ;
}
const KRVector3 & KRLight : : getColor ( ) {
return m_color ;
}
void KRLight : : setColor ( const KRVector3 & color ) {
m_color = color ;
}
void KRLight : : setDecayStart ( float decayStart ) {
m_decayStart = decayStart ;
}
float KRLight : : getDecayStart ( ) {
return m_decayStart ;
}
2012-06-15 00:05:56 +00:00
# if TARGET_OS_IPHONE
2012-11-16 02:58:23 +00:00
void KRLight : : render ( KRCamera * pCamera , std : : vector < KRLight * > & lights , const KRViewport & viewport , KRNode : : RenderPass renderPass ) {
2012-11-15 22:05:25 +00:00
KRNode : : render ( pCamera , lights , viewport , renderPass ) ;
2012-11-16 02:58:23 +00:00
if ( renderPass = = KRNode : : RENDER_PASS_GENERATE_SHADOWMAPS & & ( pCamera - > volumetric_environment_enable | | ( pCamera - > m_cShadowBuffers > 0 & & m_casts_shadow ) ) ) {
2012-11-15 22:05:25 +00:00
allocateShadowBuffers ( configureShadowBufferViewports ( viewport ) ) ;
renderShadowBuffers ( pCamera ) ;
}
2012-11-16 02:58:23 +00:00
if ( renderPass = = KRNode : : RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE & & pCamera - > volumetric_environment_enable & & m_light_shafts ) {
2012-11-15 22:05:25 +00:00
std : : string shader_name = pCamera - > volumetric_environment_downsample ! = 0 ? " volumetric_fog_downsampled " : " volumetric_fog " ;
2012-11-16 02:58:23 +00:00
std : : vector < KRLight * > this_light ;
this_light . push_back ( this ) ;
2012-11-15 22:05:25 +00:00
KRShader * pFogShader = m_pContext - > getShaderManager ( ) - > getShader ( shader_name , pCamera , this_light , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , KRNode : : RENDER_PASS_ADDITIVE_PARTICLES ) ;
2012-11-16 02:58:23 +00:00
if ( getContext ( ) . getShaderManager ( ) - > selectShader ( pFogShader , viewport , KRMat4 ( ) , this_light , KRNode : : RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE ) ) {
2012-11-15 22:05:25 +00:00
int slice_count = ( int ) ( pCamera - > volumetric_environment_quality * 495.0 ) + 5 ;
float slice_near = - pCamera - > getPerspectiveNearZ ( ) ;
float slice_far = - pCamera - > volumetric_environment_max_distance ;
float slice_spacing = ( slice_far - slice_near ) / slice_count ;
KRVector2 ( slice_near , slice_spacing ) . setUniform ( pFogShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_SLICE_DEPTH_SCALE ] ) ;
( KRVector3 : : One ( ) * pCamera - > volumetric_environment_intensity * - slice_spacing / 1000.0f ) . setUniform ( pFogShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_COLOR ] ) ;
m_pContext - > getModelManager ( ) - > bindVBO ( ( void * ) m_pContext - > getModelManager ( ) - > getVolumetricLightingVertexes ( ) , KRModelManager : : MAX_VOLUMETRIC_PLANES * 6 * sizeof ( KRModelManager : : VolumetricLightingVertexData ) , true , false , false , false , false ) ;
GLDEBUG ( glDrawArrays ( GL_TRIANGLES , 0 , slice_count * 6 ) ) ;
}
2012-06-15 00:05:56 +00:00
2012-11-15 22:05:25 +00:00
}
2012-06-15 00:05:56 +00:00
2012-11-02 20:50:45 +00:00
if ( renderPass = = KRNode : : RENDER_PASS_ADDITIVE_PARTICLES ) {
2012-06-15 00:05:56 +00:00
if ( m_flareTexture . size ( ) & & m_flareSize > 0.0f ) {
if ( ! m_pFlareTexture & & m_flareTexture . size ( ) ) {
2012-11-15 22:05:25 +00:00
m_pFlareTexture = getContext ( ) . getTextureManager ( ) - > getTexture ( m_flareTexture . c_str ( ) ) ;
2012-06-15 00:05:56 +00:00
}
if ( m_pFlareTexture ) {
2012-11-02 20:50:45 +00:00
// Disable z-buffer test
GLDEBUG ( glDisable ( GL_DEPTH_TEST ) ) ;
GLDEBUG ( glDepthRangef ( 0.0 , 1.0 ) ) ;
2012-06-15 00:05:56 +00:00
// Render light flare on transparency pass
2012-11-15 22:05:25 +00:00
KRShader * pShader = getContext ( ) . getShaderManager ( ) - > getShader ( " flare " , pCamera , lights , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , renderPass ) ;
2012-11-15 23:20:59 +00:00
if ( getContext ( ) . getShaderManager ( ) - > selectShader ( pShader , viewport , getModelMatrix ( ) , lights , renderPass ) ) {
2012-09-20 09:32:20 +00:00
GLDEBUG ( glUniform1f (
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_FLARE_SIZE ] ,
m_flareSize
) ) ;
2012-11-17 00:15:52 +00:00
m_pContext - > getTextureManager ( ) - > selectTexture ( 0 , m_pFlareTexture ) ;
2012-09-20 09:32:20 +00:00
m_pContext - > getModelManager ( ) - > bindVBO ( ( void * ) KRENGINE_VBO_2D_SQUARE , KRENGINE_VBO_2D_SQUARE_SIZE , true , false , false , true , false ) ;
GLDEBUG ( glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ) ;
}
2012-06-15 00:05:56 +00:00
}
}
}
}
2012-11-15 22:05:25 +00: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 ;
}
}
// Allocate newly required buffers
for ( int iShadow = 0 ; iShadow < cBuffers ; iShadow + + ) {
KRVector2 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 -----
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 ) ) ;
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ) ;
GLDEBUG ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ) ;
# if GL_EXT_shadow_samplers
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
# endif
GLDEBUG ( glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT , viewportSize . x , viewportSize . y , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , NULL ) ) ;
GLDEBUG ( glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , shadowDepthTexture [ iShadow ] , 0 ) ) ;
}
}
m_cShadowBuffers = cBuffers ;
}
void KRLight : : deleteBuffers ( )
{
// Called when this light wasn't used in the last frame, so we can free the resources for use by other lights
allocateShadowBuffers ( 0 ) ;
}
void KRLight : : invalidateShadowBuffers ( )
{
memset ( shadowValid , sizeof ( bool ) * KRENGINE_MAX_SHADOW_BUFFERS , 0 ) ;
}
int KRLight : : configureShadowBufferViewports ( const KRViewport & viewport )
{
return 0 ;
}
void KRLight : : renderShadowBuffers ( KRCamera * pCamera )
{
for ( int iShadow = 0 ; iShadow < m_cShadowBuffers ; iShadow + + ) {
glViewport ( 0 , 0 , m_shadowViewports [ iShadow ] . getSize ( ) . x , m_shadowViewports [ iShadow ] . getSize ( ) . y ) ;
GLDEBUG ( glBindFramebuffer ( GL_FRAMEBUFFER , shadowFramebuffer [ iShadow ] ) ) ;
2012-11-17 00:15:52 +00:00
GLDEBUG ( glClearDepthf ( 0.0f ) ) ;
GLDEBUG ( glClear ( GL_DEPTH_BUFFER_BIT ) ) ;
glViewport ( 0 , 0 , m_shadowViewports [ iShadow ] . getSize ( ) . x , m_shadowViewports [ iShadow ] . getSize ( ) . y ) ;
2012-11-15 22:05:25 +00:00
GLDEBUG ( glClearDepthf ( 1.0f ) ) ;
GLDEBUG ( glClear ( GL_DEPTH_BUFFER_BIT ) ) ;
glViewport ( 1 , 1 , m_shadowViewports [ iShadow ] . getSize ( ) . x - 2 , m_shadowViewports [ iShadow ] . getSize ( ) . y - 2 ) ;
GLDEBUG ( glDisable ( GL_DITHER ) ) ;
GLDEBUG ( glCullFace ( GL_BACK ) ) ; // Enable frontface culling, which eliminates some self-cast shadow artifacts
GLDEBUG ( glEnable ( GL_CULL_FACE ) ) ;
// Enable z-buffer test
GLDEBUG ( glEnable ( GL_DEPTH_TEST ) ) ;
GLDEBUG ( glDepthFunc ( GL_LESS ) ) ;
GLDEBUG ( glDepthRangef ( 0.0 , 1.0 ) ) ;
// Disable alpha blending as we are using alpha channel for packed depth info
GLDEBUG ( glDisable ( GL_BLEND ) ) ;
// Use shader program
2012-11-16 02:58:23 +00:00
KRShader * shadowShader = m_pContext - > getShaderManager ( ) - > getShader ( " ShadowShader " , pCamera , std : : vector < KRLight * > ( ) , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , KRNode : : RENDER_PASS_FORWARD_TRANSPARENT ) ;
2012-11-15 22:05:25 +00:00
2012-11-16 02:58:23 +00:00
getContext ( ) . getShaderManager ( ) - > selectShader ( shadowShader , m_shadowViewports [ iShadow ] , KRMat4 ( ) , std : : vector < KRLight * > ( ) , KRNode : : RENDER_PASS_SHADOWMAP ) ;
2012-11-15 22:05:25 +00:00
std : : set < KRAABB > newVisibleBounds ;
getScene ( ) . render ( pCamera , m_shadowViewports [ iShadow ] . getVisibleBounds ( ) , m_shadowViewports [ iShadow ] , KRNode : : RENDER_PASS_SHADOWMAP , newVisibleBounds ) ;
m_shadowViewports [ iShadow ] . setVisibleBounds ( newVisibleBounds ) ;
}
}
2012-06-15 00:05:56 +00:00
# endif
2012-11-16 02:58:23 +00:00
int KRLight : : getShadowBufferCount ( )
{
return m_cShadowBuffers ;
}
GLuint * KRLight : : getShadowTextures ( )
{
return shadowDepthTexture ;
}
KRViewport * KRLight : : getShadowViewports ( )
{
return m_shadowViewports ;
}