2006-02-10 22:01:20 +00:00
/*
Copyright ( C ) 2001 - 2006 , William Joseph .
All Rights Reserved .
This file is part of GtkRadiant .
GtkRadiant is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
GtkRadiant is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include "renderstate.h"
# include "debugging/debugging.h"
# include "warnings.h"
# include "ishaders.h"
# include "irender.h"
# include "itextures.h"
# include "igl.h"
# include "renderable.h"
# include "qerplugin.h"
# include <set>
# include <vector>
# include <list>
# include <map>
# include "math/matrix.h"
# include "math/aabb.h"
# include "generic/callback.h"
# include "texturelib.h"
# include "string/string.h"
# include "container/hashfunc.h"
# include "container/cache.h"
# include "generic/reference.h"
# include "moduleobservers.h"
# include "stream/filestream.h"
# include "stream/stringstream.h"
# include "os/file.h"
# include "preferences.h"
# include "xywindow.h"
# define DEBUG_RENDER 0
inline void debug_string ( const char * string )
{
# if(DEBUG_RENDER)
globalOutputStream ( ) < < string < < " \n " ;
# endif
}
inline void debug_int ( const char * comment , int i )
{
# if(DEBUG_RENDER)
globalOutputStream ( ) < < comment < < " " < < i < < " \n " ;
# endif
}
inline void debug_colour ( const char * comment )
{
# if(DEBUG_RENDER)
Vector4 v ;
glGetFloatv ( GL_CURRENT_COLOR , reinterpret_cast < float * > ( & v ) ) ;
globalOutputStream ( ) < < comment < < " colour: "
< < v [ 0 ] < < " "
< < v [ 1 ] < < " "
< < v [ 2 ] < < " "
< < v [ 3 ] ;
if ( glIsEnabled ( GL_COLOR_ARRAY ) )
{
globalOutputStream ( ) < < " ARRAY " ;
}
if ( glIsEnabled ( GL_COLOR_MATERIAL ) )
{
globalOutputStream ( ) < < " MATERIAL " ;
}
globalOutputStream ( ) < < " \n " ;
# endif
}
# include "timer.h"
StringOutputStream g_renderer_stats ;
std : : size_t g_count_prims ;
std : : size_t g_count_states ;
std : : size_t g_count_transforms ;
Timer g_timer ;
inline void count_prim ( )
{
+ + g_count_prims ;
}
inline void count_state ( )
{
+ + g_count_states ;
}
inline void count_transform ( )
{
+ + g_count_transforms ;
}
void Renderer_ResetStats ( )
{
g_count_prims = 0 ;
g_count_states = 0 ;
g_count_transforms = 0 ;
g_timer . start ( ) ;
}
const char * Renderer_GetStats ( )
{
g_renderer_stats . clear ( ) ;
g_renderer_stats < < " prims: " < < Unsigned ( g_count_prims )
< < " | states: " < < Unsigned ( g_count_states )
< < " | transforms: " < < Unsigned ( g_count_transforms )
< < " | msec: " < < g_timer . elapsed_msec ( ) ;
return g_renderer_stats . c_str ( ) ;
}
void printShaderLog ( GLhandleARB object )
{
GLint log_length = 0 ;
glGetObjectParameterivARB ( object , GL_OBJECT_INFO_LOG_LENGTH_ARB , & log_length ) ;
Array < char > log ( log_length ) ;
glGetInfoLogARB ( object , log_length , & log_length , log . data ( ) ) ;
globalErrorStream ( ) < < StringRange ( log . begin ( ) , log . begin ( ) + log_length ) < < " \n " ;
}
void createShader ( GLhandleARB program , const char * filename , GLenum type )
{
GLhandleARB shader = glCreateShaderObjectARB ( type ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
// load shader
{
std : : size_t size = file_size ( filename ) ;
FileInputStream file ( filename ) ;
ASSERT_MESSAGE ( ! file . failed ( ) , " failed to open " < < makeQuoted ( filename ) ) ;
Array < GLcharARB > buffer ( size ) ;
size = file . read ( reinterpret_cast < StreamBase : : byte_type * > ( buffer . data ( ) ) , size ) ;
const GLcharARB * string = buffer . data ( ) ;
GLint length = GLint ( size ) ;
glShaderSourceARB ( shader , 1 , & string , & length ) ;
}
// compile shader
{
glCompileShaderARB ( shader ) ;
GLint compiled = 0 ;
glGetObjectParameterivARB ( shader , GL_OBJECT_COMPILE_STATUS_ARB , & compiled ) ;
if ( ! compiled )
{
printShaderLog ( shader ) ;
}
ASSERT_MESSAGE ( compiled , " shader compile failed: " < < makeQuoted ( filename ) ) ;
}
// attach shader
glAttachObjectARB ( program , shader ) ;
glDeleteObjectARB ( shader ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void GLSLProgram_link ( GLhandleARB program )
{
glLinkProgramARB ( program ) ;
GLint linked = false ;
glGetObjectParameterivARB ( program , GL_OBJECT_LINK_STATUS_ARB , & linked ) ;
if ( ! linked )
{
printShaderLog ( program ) ;
}
ASSERT_MESSAGE ( linked , " program link failed " ) ;
}
void GLSLProgram_validate ( GLhandleARB program )
{
glValidateProgramARB ( program ) ;
GLint validated = false ;
glGetObjectParameterivARB ( program , GL_OBJECT_VALIDATE_STATUS_ARB , & validated ) ;
if ( ! validated )
{
printShaderLog ( program ) ;
}
ASSERT_MESSAGE ( validated , " program validation failed " ) ;
}
bool g_bumpGLSLPass_enabled = false ;
bool g_depthfillPass_enabled = false ;
class GLProgram
{
public :
virtual void enable ( ) = 0 ;
virtual void disable ( ) = 0 ;
virtual void setParameters ( const Vector3 & viewer , const Matrix4 & localToWorld , const Vector3 & origin , const Vector3 & colour , const Matrix4 & world2light ) = 0 ;
} ;
class GLSLBumpProgram : public GLProgram
{
public :
GLhandleARB m_program ;
qtexture_t * m_light_attenuation_xy ;
qtexture_t * m_light_attenuation_z ;
GLint u_view_origin ;
GLint u_light_origin ;
GLint u_light_color ;
GLint u_bump_scale ;
GLint u_specular_exponent ;
GLSLBumpProgram ( ) : m_program ( 0 ) , m_light_attenuation_xy ( 0 ) , m_light_attenuation_z ( 0 )
{
}
void create ( )
{
// create program
m_program = glCreateProgramObjectARB ( ) ;
// create shader
{
StringOutputStream filename ( 256 ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_vp.glsl " ;
createShader ( m_program , filename . c_str ( ) , GL_VERTEX_SHADER_ARB ) ;
filename . clear ( ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_fp.glsl " ;
createShader ( m_program , filename . c_str ( ) , GL_FRAGMENT_SHADER_ARB ) ;
}
GLSLProgram_link ( m_program ) ;
GLSLProgram_validate ( m_program ) ;
glUseProgramObjectARB ( m_program ) ;
glBindAttribLocationARB ( m_program , c_attr_TexCoord0 , " attr_TexCoord0 " ) ;
glBindAttribLocationARB ( m_program , c_attr_Tangent , " attr_Tangent " ) ;
glBindAttribLocationARB ( m_program , c_attr_Binormal , " attr_Binormal " ) ;
glUniform1iARB ( glGetUniformLocationARB ( m_program , " u_diffusemap " ) , 0 ) ;
glUniform1iARB ( glGetUniformLocationARB ( m_program , " u_bumpmap " ) , 1 ) ;
glUniform1iARB ( glGetUniformLocationARB ( m_program , " u_specularmap " ) , 2 ) ;
glUniform1iARB ( glGetUniformLocationARB ( m_program , " u_attenuationmap_xy " ) , 3 ) ;
glUniform1iARB ( glGetUniformLocationARB ( m_program , " u_attenuationmap_z " ) , 4 ) ;
u_view_origin = glGetUniformLocationARB ( m_program , " u_view_origin " ) ;
u_light_origin = glGetUniformLocationARB ( m_program , " u_light_origin " ) ;
u_light_color = glGetUniformLocationARB ( m_program , " u_light_color " ) ;
u_bump_scale = glGetUniformLocationARB ( m_program , " u_bump_scale " ) ;
u_specular_exponent = glGetUniformLocationARB ( m_program , " u_specular_exponent " ) ;
glUseProgramObjectARB ( 0 ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void destroy ( )
{
glDeleteObjectARB ( m_program ) ;
m_program = 0 ;
}
void enable ( )
{
glUseProgramObjectARB ( m_program ) ;
glEnableVertexAttribArrayARB ( c_attr_TexCoord0 ) ;
glEnableVertexAttribArrayARB ( c_attr_Tangent ) ;
glEnableVertexAttribArrayARB ( c_attr_Binormal ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_string ( " enable bump " ) ;
g_bumpGLSLPass_enabled = true ;
}
void disable ( )
{
glUseProgramObjectARB ( 0 ) ;
glDisableVertexAttribArrayARB ( c_attr_TexCoord0 ) ;
glDisableVertexAttribArrayARB ( c_attr_Tangent ) ;
glDisableVertexAttribArrayARB ( c_attr_Binormal ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_string ( " disable bump " ) ;
g_bumpGLSLPass_enabled = false ;
}
void setParameters ( const Vector3 & viewer , const Matrix4 & localToWorld , const Vector3 & origin , const Vector3 & colour , const Matrix4 & world2light )
{
Matrix4 world2local ( localToWorld ) ;
matrix4_affine_invert ( world2local ) ;
Vector3 localLight ( origin ) ;
matrix4_transform_point ( world2local , localLight ) ;
Vector3 localViewer ( viewer ) ;
matrix4_transform_point ( world2local , localViewer ) ;
Matrix4 local2light ( world2light ) ;
matrix4_multiply_by_matrix4 ( local2light , localToWorld ) ; // local->world->light
glUniform3fARB ( u_view_origin , localViewer . x ( ) , localViewer . y ( ) , localViewer . z ( ) ) ;
glUniform3fARB ( u_light_origin , localLight . x ( ) , localLight . y ( ) , localLight . z ( ) ) ;
glUniform3fARB ( u_light_color , colour . x ( ) , colour . y ( ) , colour . z ( ) ) ;
glUniform1fARB ( u_bump_scale , 1.0 ) ;
glUniform1fARB ( u_specular_exponent , 32.0 ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glClientActiveTexture ( GL_TEXTURE3 ) ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & local2light ) ) ;
glMatrixMode ( GL_MODELVIEW ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
} ;
GLSLBumpProgram g_bumpGLSL ;
class GLSLDepthFillProgram : public GLProgram
{
public :
GLhandleARB m_program ;
void create ( )
{
// create program
m_program = glCreateProgramObjectARB ( ) ;
// create shader
{
StringOutputStream filename ( 256 ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/zfill_vp.glsl " ;
createShader ( m_program , filename . c_str ( ) , GL_VERTEX_SHADER_ARB ) ;
filename . clear ( ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/zfill_fp.glsl " ;
createShader ( m_program , filename . c_str ( ) , GL_FRAGMENT_SHADER_ARB ) ;
}
GLSLProgram_link ( m_program ) ;
GLSLProgram_validate ( m_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void destroy ( )
{
glDeleteObjectARB ( m_program ) ;
m_program = 0 ;
}
void enable ( )
{
glUseProgramObjectARB ( m_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_string ( " enable depthfill " ) ;
g_depthfillPass_enabled = true ;
}
void disable ( )
{
glUseProgramObjectARB ( 0 ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_string ( " disable depthfill " ) ;
g_depthfillPass_enabled = false ;
}
void setParameters ( const Vector3 & viewer , const Matrix4 & localToWorld , const Vector3 & origin , const Vector3 & colour , const Matrix4 & world2light )
{
}
} ;
GLSLDepthFillProgram g_depthFillGLSL ;
// ARB path
void createProgram ( const char * filename , GLenum type )
{
std : : size_t size = file_size ( filename ) ;
FileInputStream file ( filename ) ;
ASSERT_MESSAGE ( ! file . failed ( ) , " failed to open " < < makeQuoted ( filename ) ) ;
Array < GLcharARB > buffer ( size ) ;
size = file . read ( reinterpret_cast < StreamBase : : byte_type * > ( buffer . data ( ) ) , size ) ;
glProgramStringARB ( type , GL_PROGRAM_FORMAT_ASCII_ARB , GLsizei ( size ) , buffer . data ( ) ) ;
if ( GL_INVALID_OPERATION = = glGetError ( ) )
{
GLint errPos ;
glGetIntegerv ( GL_PROGRAM_ERROR_POSITION_ARB , & errPos ) ;
const GLubyte * errString = glGetString ( GL_PROGRAM_ERROR_STRING_ARB ) ;
globalErrorStream ( ) < < reinterpret_cast < const char * > ( filename ) < < " : " < < errPos < < " \n " < < reinterpret_cast < const char * > ( errString ) ;
ERROR_MESSAGE ( " error in gl program " ) ;
}
}
class ARBBumpProgram : public GLProgram
{
public :
GLuint m_vertex_program ;
GLuint m_fragment_program ;
void create ( )
{
glEnable ( GL_VERTEX_PROGRAM_ARB ) ;
glEnable ( GL_FRAGMENT_PROGRAM_ARB ) ;
{
glGenProgramsARB ( 1 , & m_vertex_program ) ;
glBindProgramARB ( GL_VERTEX_PROGRAM_ARB , m_vertex_program ) ;
StringOutputStream filename ( 256 ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_vp.glp " ;
createProgram ( filename . c_str ( ) , GL_VERTEX_PROGRAM_ARB ) ;
glGenProgramsARB ( 1 , & m_fragment_program ) ;
glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB , m_fragment_program ) ;
filename . clear ( ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_fp.glp " ;
createProgram ( filename . c_str ( ) , GL_FRAGMENT_PROGRAM_ARB ) ;
}
glDisable ( GL_VERTEX_PROGRAM_ARB ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void destroy ( )
{
glDeleteProgramsARB ( 1 , & m_vertex_program ) ;
glDeleteProgramsARB ( 1 , & m_fragment_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void enable ( )
{
glEnable ( GL_VERTEX_PROGRAM_ARB ) ;
glEnable ( GL_FRAGMENT_PROGRAM_ARB ) ;
glBindProgramARB ( GL_VERTEX_PROGRAM_ARB , m_vertex_program ) ;
glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB , m_fragment_program ) ;
glEnableVertexAttribArrayARB ( 8 ) ;
glEnableVertexAttribArrayARB ( 9 ) ;
glEnableVertexAttribArrayARB ( 10 ) ;
glEnableVertexAttribArrayARB ( 11 ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void disable ( )
{
glDisable ( GL_VERTEX_PROGRAM_ARB ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
glDisableVertexAttribArrayARB ( 8 ) ;
glDisableVertexAttribArrayARB ( 9 ) ;
glDisableVertexAttribArrayARB ( 10 ) ;
glDisableVertexAttribArrayARB ( 11 ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void setParameters ( const Vector3 & viewer , const Matrix4 & localToWorld , const Vector3 & origin , const Vector3 & colour , const Matrix4 & world2light )
{
Matrix4 world2local ( localToWorld ) ;
matrix4_affine_invert ( world2local ) ;
Vector3 localLight ( origin ) ;
matrix4_transform_point ( world2local , localLight ) ;
Vector3 localViewer ( viewer ) ;
matrix4_transform_point ( world2local , localViewer ) ;
Matrix4 local2light ( world2light ) ;
matrix4_multiply_by_matrix4 ( local2light , localToWorld ) ; // local->world->light
// view origin
glProgramLocalParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB , 4 , localViewer . x ( ) , localViewer . y ( ) , localViewer . z ( ) , 0 ) ;
// light origin
glProgramLocalParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB , 2 , localLight . x ( ) , localLight . y ( ) , localLight . z ( ) , 1 ) ;
// light colour
glProgramLocalParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB , 3 , colour . x ( ) , colour . y ( ) , colour . z ( ) , 0 ) ;
// bump scale
glProgramLocalParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB , 1 , 1 , 0 , 0 , 0 ) ;
// specular exponent
glProgramLocalParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB , 5 , 32 , 0 , 0 , 0 ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glClientActiveTexture ( GL_TEXTURE3 ) ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & local2light ) ) ;
glMatrixMode ( GL_MODELVIEW ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
} ;
class ARBDepthFillProgram : public GLProgram
{
public :
GLuint m_vertex_program ;
GLuint m_fragment_program ;
void create ( )
{
glEnable ( GL_VERTEX_PROGRAM_ARB ) ;
glEnable ( GL_FRAGMENT_PROGRAM_ARB ) ;
{
glGenProgramsARB ( 1 , & m_vertex_program ) ;
glBindProgramARB ( GL_VERTEX_PROGRAM_ARB , m_vertex_program ) ;
StringOutputStream filename ( 256 ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/zfill_vp.glp " ;
createProgram ( filename . c_str ( ) , GL_VERTEX_PROGRAM_ARB ) ;
glGenProgramsARB ( 1 , & m_fragment_program ) ;
glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB , m_fragment_program ) ;
filename . clear ( ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/zfill_fp.glp " ;
createProgram ( filename . c_str ( ) , GL_FRAGMENT_PROGRAM_ARB ) ;
}
glDisable ( GL_VERTEX_PROGRAM_ARB ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void destroy ( )
{
glDeleteProgramsARB ( 1 , & m_vertex_program ) ;
glDeleteProgramsARB ( 1 , & m_fragment_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void enable ( )
{
glEnable ( GL_VERTEX_PROGRAM_ARB ) ;
glEnable ( GL_FRAGMENT_PROGRAM_ARB ) ;
glBindProgramARB ( GL_VERTEX_PROGRAM_ARB , m_vertex_program ) ;
glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB , m_fragment_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void disable ( )
{
glDisable ( GL_VERTEX_PROGRAM_ARB ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void setParameters ( const Vector3 & viewer , const Matrix4 & localToWorld , const Vector3 & origin , const Vector3 & colour , const Matrix4 & world2light )
{
}
} ;
ARBBumpProgram g_bumpARB ;
ARBDepthFillProgram g_depthFillARB ;
#if 0
// NV20 path (unfinished)
void createProgram ( GLint program , const char * filename , GLenum type )
{
std : : size_t size = file_size ( filename ) ;
FileInputStream file ( filename ) ;
ASSERT_MESSAGE ( ! file . failed ( ) , " failed to open " < < makeQuoted ( filename ) ) ;
Array < GLubyte > buffer ( size ) ;
size = file . read ( reinterpret_cast < StreamBase : : byte_type * > ( buffer . data ( ) ) , size ) ;
glLoadProgramNV ( type , program , GLsizei ( size ) , buffer . data ( ) ) ;
if ( GL_INVALID_OPERATION = = glGetError ( ) )
{
GLint errPos ;
glGetIntegerv ( GL_PROGRAM_ERROR_POSITION_NV , & errPos ) ;
const GLubyte * errString = glGetString ( GL_PROGRAM_ERROR_STRING_NV ) ;
globalErrorStream ( ) < < filename < < " : " < < errPos < < " \n " < < errString ;
ERROR_MESSAGE ( " error in gl program " ) ;
}
}
GLuint m_vertex_program ;
GLuint m_fragment_program ;
qtexture_t * g_cube = 0 ;
qtexture_t * g_specular_lookup = 0 ;
qtexture_t * g_attenuation_xy = 0 ;
qtexture_t * g_attenuation_z = 0 ;
void createVertexProgram ( )
{
{
glGenProgramsNV ( 1 , & m_vertex_program ) ;
glBindProgramNV ( GL_VERTEX_PROGRAM_NV , m_vertex_program ) ;
StringOutputStream filename ( 256 ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_vp.nv30 " ;
createProgram ( m_vertex_program , filename . c_str ( ) , GL_VERTEX_PROGRAM_NV ) ;
glGenProgramsNV ( 1 , & m_fragment_program ) ;
glBindProgramNV ( GL_FRAGMENT_PROGRAM_NV , m_fragment_program ) ;
filename . clear ( ) ;
filename < < GlobalRadiant ( ) . getAppPath ( ) < < " gl/lighting_DBS_omni_fp.nv30 " ;
createProgram ( m_fragment_program , filename . c_str ( ) , GL_FRAGMENT_PROGRAM_NV ) ;
}
g_cube = GlobalTexturesCache ( ) . capture ( " generated/cube " ) ;
g_specular_lookup = GlobalTexturesCache ( ) . capture ( " generated/specular " ) ;
g_attenuation_xy = GlobalTexturesCache ( ) . capture ( " lights/squarelight1 " ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , g_attenuation_xy - > texture_number ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
g_attenuation_z = GlobalTexturesCache ( ) . capture ( " lights/squarelight1a " ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , g_attenuation_z - > texture_number ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void destroyVertexProgram ( )
{
glDeleteProgramsNV ( 1 , & m_vertex_program ) ;
glDeleteProgramsNV ( 1 , & m_fragment_program ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
GlobalTexturesCache ( ) . release ( g_cube ) ;
GlobalTexturesCache ( ) . release ( g_specular_lookup ) ;
GlobalTexturesCache ( ) . release ( g_attenuation_xy ) ;
GlobalTexturesCache ( ) . release ( g_attenuation_z ) ;
}
bool g_vertexProgram_enabled = false ;
void enableVertexProgram ( )
{
//set up the register combiners
//two general combiners
glCombinerParameteriNV ( GL_NUM_GENERAL_COMBINERS_NV , 2 ) ;
//combiner 0 does tex0+tex1 -> spare0
glCombinerInputNV ( GL_COMBINER0_NV , GL_RGB , GL_VARIABLE_A_NV , GL_TEXTURE0_ARB ,
GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glCombinerInputNV ( GL_COMBINER0_NV , GL_RGB , GL_VARIABLE_B_NV , GL_ZERO ,
GL_UNSIGNED_INVERT_NV , GL_RGB ) ;
glCombinerInputNV ( GL_COMBINER0_NV , GL_RGB , GL_VARIABLE_C_NV , GL_TEXTURE1_ARB ,
GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glCombinerInputNV ( GL_COMBINER0_NV , GL_RGB , GL_VARIABLE_D_NV , GL_ZERO ,
GL_UNSIGNED_INVERT_NV , GL_RGB ) ;
glCombinerOutputNV ( GL_COMBINER0_NV , GL_RGB , GL_DISCARD_NV , GL_DISCARD_NV , GL_SPARE0_NV ,
GL_NONE , GL_NONE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
//combiner 1 does tex2 dot tex3 -> spare1
glCombinerInputNV ( GL_COMBINER1_NV , GL_RGB , GL_VARIABLE_A_NV , GL_TEXTURE2_ARB ,
GL_EXPAND_NORMAL_NV , GL_RGB ) ;
glCombinerInputNV ( GL_COMBINER1_NV , GL_RGB , GL_VARIABLE_B_NV , GL_TEXTURE3_ARB ,
GL_EXPAND_NORMAL_NV , GL_RGB ) ;
glCombinerOutputNV ( GL_COMBINER1_NV , GL_RGB , GL_SPARE1_NV , GL_DISCARD_NV , GL_DISCARD_NV ,
GL_NONE , GL_NONE , GL_TRUE , GL_FALSE , GL_FALSE ) ;
//final combiner outputs (1-spare0)*constant color 0*spare1
//do constant color 0*spare1 in the EF multiplier
glFinalCombinerInputNV ( GL_VARIABLE_E_NV , GL_SPARE1_NV , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glFinalCombinerInputNV ( GL_VARIABLE_F_NV , GL_CONSTANT_COLOR0_NV , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
//now do (1-spare0)*EF
glFinalCombinerInputNV ( GL_VARIABLE_A_NV , GL_SPARE0_NV , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glFinalCombinerInputNV ( GL_VARIABLE_B_NV , GL_ZERO , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glFinalCombinerInputNV ( GL_VARIABLE_C_NV , GL_E_TIMES_F_NV , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glFinalCombinerInputNV ( GL_VARIABLE_D_NV , GL_ZERO , GL_UNSIGNED_IDENTITY_NV , GL_RGB ) ;
glEnable ( GL_VERTEX_PROGRAM_NV ) ;
glEnable ( GL_REGISTER_COMBINERS_NV ) ;
glBindProgramNV ( GL_VERTEX_PROGRAM_NV , m_vertex_program ) ;
glBindProgramNV ( GL_FRAGMENT_PROGRAM_NV , m_fragment_program ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glEnable ( GL_TEXTURE_2D ) ;
glActiveTexture ( GL_TEXTURE1 ) ;
glEnable ( GL_TEXTURE_1D ) ;
glActiveTexture ( GL_TEXTURE2 ) ;
glEnable ( GL_TEXTURE_2D ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glEnable ( GL_TEXTURE_2D ) ;
glEnableClientState ( GL_VERTEX_ATTRIB_ARRAY8_NV ) ;
glEnableClientState ( GL_VERTEX_ATTRIB_ARRAY9_NV ) ;
glEnableClientState ( GL_VERTEX_ATTRIB_ARRAY10_NV ) ;
glEnableClientState ( GL_VERTEX_ATTRIB_ARRAY11_NV ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_vertexProgram_enabled = true ;
}
void disableVertexProgram ( )
{
glDisable ( GL_VERTEX_PROGRAM_NV ) ;
glDisable ( GL_REGISTER_COMBINERS_NV ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glDisable ( GL_TEXTURE_2D ) ;
glActiveTexture ( GL_TEXTURE1 ) ;
glDisable ( GL_TEXTURE_1D ) ;
glActiveTexture ( GL_TEXTURE2 ) ;
glDisable ( GL_TEXTURE_2D ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisableClientState ( GL_VERTEX_ATTRIB_ARRAY8_NV ) ;
glDisableClientState ( GL_VERTEX_ATTRIB_ARRAY9_NV ) ;
glDisableClientState ( GL_VERTEX_ATTRIB_ARRAY10_NV ) ;
glDisableClientState ( GL_VERTEX_ATTRIB_ARRAY11_NV ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_vertexProgram_enabled = false ;
}
class GLstringNV
{
public :
const GLubyte * m_string ;
const GLint m_length ;
GLstringNV ( const char * string ) : m_string ( reinterpret_cast < const GLubyte * > ( string ) ) , m_length ( GLint ( string_length ( string ) ) )
{
}
} ;
GLstringNV g_light_origin ( " light_origin " ) ;
GLstringNV g_view_origin ( " view_origin " ) ;
GLstringNV g_light_color ( " light_color " ) ;
GLstringNV g_bumpGLSL_scale ( " bump_scale " ) ;
GLstringNV g_specular_exponent ( " specular_exponent " ) ;
void setVertexProgramEnvironment ( const Vector3 & localViewer )
{
Matrix4 local2light ( g_matrix4_identity ) ;
matrix4_translate_by_vec3 ( local2light , Vector3 ( 0.5 , 0.5 , 0.5 ) ) ;
matrix4_scale_by_vec3 ( local2light , Vector3 ( 0.5 , 0.5 , 0.5 ) ) ;
matrix4_scale_by_vec3 ( local2light , Vector3 ( 1.0 / 512.0 , 1.0 / 512.0 , 1.0 / 512.0 ) ) ;
matrix4_translate_by_vec3 ( local2light , vector3_negated ( localViewer ) ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glClientActiveTexture ( GL_TEXTURE3 ) ;
glMatrixMode ( GL_TEXTURE ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & local2light ) ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glTrackMatrixNV ( GL_VERTEX_PROGRAM_NV , 0 , GL_MODELVIEW_PROJECTION_NV , GL_IDENTITY_NV ) ;
glTrackMatrixNV ( GL_VERTEX_PROGRAM_NV , 4 , GL_TEXTURE0_ARB , GL_IDENTITY_NV ) ;
// view origin
//qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
// light origin
glProgramParameter4fNV ( GL_VERTEX_PROGRAM_NV , 8 , localViewer . x ( ) , localViewer . y ( ) , localViewer . z ( ) , 1.0f ) ;
// light colour
glCombinerParameterfNV ( GL_CONSTANT_COLOR0_NV , 1 , 1 , 1 , 1 )
// bump scale
//qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
// specular exponent
//qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
# endif
bool g_vertexArray_enabled = false ;
bool g_normalArray_enabled = false ;
bool g_texcoordArray_enabled = false ;
bool g_colorArray_enabled = false ;
//! A collection of opengl state information.
class OpenGLState
{
public :
enum ESort
{
eSortFirst = 0 ,
eSortOpaque = 1 ,
eSortMultiFirst = 2 ,
eSortMultiLast = 1023 ,
eSortOverbrighten = 1024 ,
eSortFullbright = 1025 ,
eSortHighlight = 1026 ,
eSortTranslucent = 1027 ,
eSortOverlayFirst = 1028 ,
eSortOverlayLast = 2047 ,
eSortControlFirst = 2048 ,
eSortControlLast = 3071 ,
eSortGUI0 = 3072 ,
eSortGUI1 = 3073 ,
eSortLast = 4096 ,
} ;
unsigned int m_state ;
std : : size_t m_sort ;
GLint m_texture ;
GLint m_texture1 ;
GLint m_texture2 ;
GLint m_texture3 ;
GLint m_texture4 ;
GLint m_texture5 ;
GLint m_texture6 ;
GLint m_texture7 ;
Vector4 m_colour ;
GLenum m_blend_src , m_blend_dst ;
GLenum m_depthfunc ;
GLenum m_alphafunc ;
GLfloat m_alpharef ;
GLfloat m_linewidth ;
GLfloat m_pointsize ;
GLint m_linestipple_factor ;
GLushort m_linestipple_pattern ;
GLProgram * m_program ;
OpenGLState ( ) : m_program ( 0 )
{
}
} ;
inline bool OpenGLState_less ( const OpenGLState & self , const OpenGLState & other )
{
//! Sort by sort-order override.
if ( self . m_sort ! = other . m_sort )
{
return self . m_sort < other . m_sort ;
}
//! Sort by texture handle.
if ( self . m_texture ! = other . m_texture )
{
return self . m_texture < other . m_texture ;
}
if ( self . m_texture1 ! = other . m_texture1 )
{
return self . m_texture1 < other . m_texture1 ;
}
if ( self . m_texture2 ! = other . m_texture2 )
{
return self . m_texture2 < other . m_texture2 ;
}
if ( self . m_texture3 ! = other . m_texture3 )
{
return self . m_texture3 < other . m_texture3 ;
}
if ( self . m_texture4 ! = other . m_texture4 )
{
return self . m_texture4 < other . m_texture4 ;
}
if ( self . m_texture5 ! = other . m_texture5 )
{
return self . m_texture5 < other . m_texture5 ;
}
if ( self . m_texture6 ! = other . m_texture6 )
{
return self . m_texture6 < other . m_texture6 ;
}
if ( self . m_texture7 ! = other . m_texture7 )
{
return self . m_texture7 < other . m_texture7 ;
}
//! Sort by state bit-vector.
if ( self . m_state ! = other . m_state )
{
return self . m_state < other . m_state ;
}
//! Comparing address makes sure states are never equal.
return & self < & other ;
}
void OpenGLState_constructDefault ( OpenGLState & state )
{
state . m_state = RENDER_DEFAULT ;
state . m_texture = 0 ;
state . m_texture1 = 0 ;
state . m_texture2 = 0 ;
state . m_texture3 = 0 ;
state . m_texture4 = 0 ;
state . m_texture5 = 0 ;
state . m_texture6 = 0 ;
state . m_texture7 = 0 ;
state . m_colour [ 0 ] = 1 ;
state . m_colour [ 1 ] = 1 ;
state . m_colour [ 2 ] = 1 ;
state . m_colour [ 3 ] = 1 ;
state . m_depthfunc = GL_LESS ;
state . m_blend_src = GL_SRC_ALPHA ;
state . m_blend_dst = GL_ONE_MINUS_SRC_ALPHA ;
state . m_alphafunc = GL_ALWAYS ;
state . m_alpharef = 0 ;
state . m_linewidth = 1 ;
state . m_pointsize = 1 ;
state . m_linestipple_factor = 1 ;
state . m_linestipple_pattern = 0xaaaa ;
}
/// \brief A container of Renderable references.
/// May contain the same Renderable multiple times, with different transforms.
class OpenGLStateBucket
{
public :
struct RenderTransform
{
const Matrix4 * m_transform ;
const OpenGLRenderable * m_renderable ;
const RendererLight * m_light ;
RenderTransform ( const OpenGLRenderable & renderable , const Matrix4 & transform , const RendererLight * light )
: m_transform ( & transform ) , m_renderable ( & renderable ) , m_light ( light )
{
}
} ;
typedef std : : vector < RenderTransform > Renderables ;
private :
OpenGLState m_state ;
Renderables m_renderables ;
public :
OpenGLStateBucket ( )
{
}
void addRenderable ( const OpenGLRenderable & renderable , const Matrix4 & modelview , const RendererLight * light = 0 )
{
m_renderables . push_back ( RenderTransform ( renderable , modelview , light ) ) ;
}
OpenGLState & state ( )
{
return m_state ;
}
void render ( OpenGLState & current , unsigned int globalstate , const Vector3 & viewer ) ;
} ;
# define LIGHT_SHADER_DEBUG 0
# if LIGHT_SHADER_DEBUG
typedef std : : vector < Shader * > LightDebugShaders ;
LightDebugShaders g_lightDebugShaders ;
# endif
class OpenGLStateLess
{
public :
bool operator ( ) ( const OpenGLState & self , const OpenGLState & other ) const
{
return OpenGLState_less ( self , other ) ;
}
} ;
typedef ConstReference < OpenGLState > OpenGLStateReference ;
typedef std : : map < OpenGLStateReference , OpenGLStateBucket * , OpenGLStateLess > OpenGLStates ;
OpenGLStates g_state_sorted ;
class OpenGLStateBucketAdd
{
OpenGLStateBucket & m_bucket ;
const OpenGLRenderable & m_renderable ;
const Matrix4 & m_modelview ;
public :
typedef const RendererLight & first_argument_type ;
OpenGLStateBucketAdd ( OpenGLStateBucket & bucket , const OpenGLRenderable & renderable , const Matrix4 & modelview ) :
m_bucket ( bucket ) , m_renderable ( renderable ) , m_modelview ( modelview )
{
}
void operator ( ) ( const RendererLight & light )
{
m_bucket . addRenderable ( m_renderable , m_modelview , & light ) ;
}
} ;
class CountLights
{
std : : size_t m_count ;
public :
typedef RendererLight & first_argument_type ;
CountLights ( ) : m_count ( 0 )
{
}
void operator ( ) ( const RendererLight & light )
{
+ + m_count ;
}
std : : size_t count ( ) const
{
return m_count ;
}
} ;
class OpenGLShader : public Shader
{
typedef std : : list < OpenGLStateBucket * > Passes ;
Passes m_passes ;
IShader * m_shader ;
std : : size_t m_used ;
ModuleObservers m_observers ;
public :
OpenGLShader ( ) : m_shader ( 0 ) , m_used ( 0 )
{
}
~ OpenGLShader ( )
{
}
void construct ( const char * name ) ;
void destroy ( )
{
if ( m_shader )
{
m_shader - > DecRef ( ) ;
}
m_shader = 0 ;
for ( Passes : : iterator i = m_passes . begin ( ) ; i ! = m_passes . end ( ) ; + + i )
{
delete * i ;
}
m_passes . clear ( ) ;
}
void addRenderable ( const OpenGLRenderable & renderable , const Matrix4 & modelview , const LightList * lights )
{
for ( Passes : : iterator i = m_passes . begin ( ) ; i ! = m_passes . end ( ) ; + + i )
{
# if LIGHT_SHADER_DEBUG
if ( ( ( * i ) - > state ( ) . m_state & RENDER_BUMP ) ! = 0 )
{
if ( lights ! = 0 )
{
CountLights counter ;
lights - > forEachLight ( makeCallback1 ( counter ) ) ;
globalOutputStream ( ) < < " count = " < < counter . count ( ) < < " \n " ;
for ( std : : size_t i = 0 ; i < counter . count ( ) ; + + i )
{
g_lightDebugShaders [ counter . count ( ) ] - > addRenderable ( renderable , modelview ) ;
}
}
}
else
# else
if ( ( ( * i ) - > state ( ) . m_state & RENDER_BUMP ) ! = 0 )
{
if ( lights ! = 0 )
{
OpenGLStateBucketAdd add ( * ( * i ) , renderable , modelview ) ;
lights - > forEachLight ( makeCallback1 ( add ) ) ;
}
}
else
# endif
{
( * i ) - > addRenderable ( renderable , modelview ) ;
}
}
}
void incrementUsed ( )
{
if ( + + m_used = = 1 & & m_shader ! = 0 )
{
m_shader - > SetInUse ( true ) ;
}
}
void decrementUsed ( )
{
if ( - - m_used = = 0 & & m_shader ! = 0 )
{
m_shader - > SetInUse ( false ) ;
}
}
bool realised ( ) const
{
return m_shader ! = 0 ;
}
void attach ( ModuleObserver & observer )
{
if ( realised ( ) )
{
observer . realise ( ) ;
}
m_observers . attach ( observer ) ;
}
void detach ( ModuleObserver & observer )
{
if ( realised ( ) )
{
observer . unrealise ( ) ;
}
m_observers . detach ( observer ) ;
}
void realise ( const CopiedString & name )
{
construct ( name . c_str ( ) ) ;
if ( m_used ! = 0 & & m_shader ! = 0 )
{
m_shader - > SetInUse ( true ) ;
}
for ( Passes : : iterator i = m_passes . begin ( ) ; i ! = m_passes . end ( ) ; + + i )
{
g_state_sorted . insert ( OpenGLStates : : value_type ( OpenGLStateReference ( ( * i ) - > state ( ) ) , * i ) ) ;
}
m_observers . realise ( ) ;
}
void unrealise ( )
{
m_observers . unrealise ( ) ;
for ( Passes : : iterator i = m_passes . begin ( ) ; i ! = m_passes . end ( ) ; + + i )
{
g_state_sorted . erase ( OpenGLStateReference ( ( * i ) - > state ( ) ) ) ;
}
destroy ( ) ;
}
qtexture_t & getTexture ( ) const
{
ASSERT_NOTNULL ( m_shader ) ;
return * m_shader - > getTexture ( ) ;
}
unsigned int getFlags ( ) const
{
ASSERT_NOTNULL ( m_shader ) ;
return m_shader - > getFlags ( ) ;
}
IShader & getShader ( ) const
{
ASSERT_NOTNULL ( m_shader ) ;
return * m_shader ;
}
OpenGLState & appendDefaultPass ( )
{
m_passes . push_back ( new OpenGLStateBucket ) ;
OpenGLState & state = m_passes . back ( ) - > state ( ) ;
OpenGLState_constructDefault ( state ) ;
return state ;
}
} ;
inline bool lightEnabled ( const RendererLight & light , const LightCullable & cullable )
{
return cullable . testLight ( light ) ;
}
typedef std : : set < RendererLight * > RendererLights ;
# define DEBUG_LIGHT_SYNC 0
class LinearLightList : public LightList
{
LightCullable & m_cullable ;
RendererLights & m_allLights ;
Callback m_evaluateChanged ;
typedef std : : list < RendererLight * > Lights ;
mutable Lights m_lights ;
mutable bool m_lightsChanged ;
public :
LinearLightList ( LightCullable & cullable , RendererLights & lights , const Callback & evaluateChanged ) :
m_cullable ( cullable ) , m_allLights ( lights ) , m_evaluateChanged ( evaluateChanged )
{
m_lightsChanged = true ;
}
void evaluateLights ( ) const
{
m_evaluateChanged ( ) ;
if ( m_lightsChanged )
{
m_lightsChanged = false ;
m_lights . clear ( ) ;
m_cullable . clearLights ( ) ;
for ( RendererLights : : const_iterator i = m_allLights . begin ( ) ; i ! = m_allLights . end ( ) ; + + i )
{
if ( lightEnabled ( * ( * i ) , m_cullable ) )
{
m_lights . push_back ( * i ) ;
m_cullable . insertLight ( * ( * i ) ) ;
}
}
}
# if(DEBUG_LIGHT_SYNC)
else
{
Lights lights ;
for ( RendererLights : : const_iterator i = m_allLights . begin ( ) ; i ! = m_allLights . end ( ) ; + + i )
{
if ( lightEnabled ( * ( * i ) , m_cullable ) )
{
lights . push_back ( * i ) ;
}
}
ASSERT_MESSAGE (
! std : : lexicographical_compare ( lights . begin ( ) , lights . end ( ) , m_lights . begin ( ) , m_lights . end ( ) )
& & ! std : : lexicographical_compare ( m_lights . begin ( ) , m_lights . end ( ) , lights . begin ( ) , lights . end ( ) ) ,
" lights out of sync "
) ;
}
# endif
}
void forEachLight ( const RendererLightCallback & callback ) const
{
evaluateLights ( ) ;
for ( Lights : : const_iterator i = m_lights . begin ( ) ; i ! = m_lights . end ( ) ; + + i )
{
callback ( * ( * i ) ) ;
}
}
void lightsChanged ( ) const
{
m_lightsChanged = true ;
}
} ;
# define DEBUG_SHADERS 0
class OpenGLShaderCache : public ShaderCache , public TexturesCacheObserver , public ModuleObserver
{
class CreateOpenGLShader
{
OpenGLShaderCache * m_cache ;
public :
explicit CreateOpenGLShader ( OpenGLShaderCache * cache = 0 )
: m_cache ( cache )
{
}
OpenGLShader * construct ( const CopiedString & name )
{
OpenGLShader * shader = new OpenGLShader ;
if ( m_cache - > realised ( ) )
{
shader - > realise ( name ) ;
}
return shader ;
}
void destroy ( OpenGLShader * shader )
{
if ( m_cache - > realised ( ) )
{
shader - > unrealise ( ) ;
}
delete shader ;
}
} ;
typedef HashedCache < CopiedString , OpenGLShader , HashString , std : : equal_to < CopiedString > , CreateOpenGLShader > Shaders ;
Shaders m_shaders ;
std : : size_t m_unrealised ;
bool m_lightingEnabled ;
bool m_lightingSupported ;
bool m_useShaderLanguage ;
public :
OpenGLShaderCache ( )
: m_shaders ( CreateOpenGLShader ( this ) ) ,
m_unrealised ( 3 ) , // wait until shaders, gl-context and textures are realised before creating any render-states
m_lightingEnabled ( true ) ,
m_lightingSupported ( false ) ,
m_useShaderLanguage ( false ) ,
m_lightsChanged ( true ) ,
m_traverseRenderablesMutex ( false )
{
}
~ OpenGLShaderCache ( )
{
for ( Shaders : : iterator i = m_shaders . begin ( ) ; i ! = m_shaders . end ( ) ; + + i )
{
globalOutputStream ( ) < < " leaked shader: " < < makeQuoted ( ( * i ) . key . c_str ( ) ) < < " \n " ;
}
}
Shader * capture ( const char * name )
{
ASSERT_MESSAGE ( name [ 0 ] = = ' $ '
| | * name = = ' [ '
| | * name = = ' < '
| | * name = = ' ( '
| | strchr ( name , ' \\ ' ) = = 0 , " shader name contains invalid characters: \" " < < name < < " \" " ) ;
# if DEBUG_SHADERS
globalOutputStream ( ) < < " shaders capture: " < < makeQuoted ( name ) < < ' \n ' ;
# endif
return m_shaders . capture ( name ) . get ( ) ;
}
void release ( const char * name )
{
# if DEBUG_SHADERS
globalOutputStream ( ) < < " shaders release: " < < makeQuoted ( name ) < < ' \n ' ;
# endif
m_shaders . release ( name ) ;
}
void render ( RenderStateFlags globalstate , const Matrix4 & modelview , const Matrix4 & projection , const Vector3 & viewer )
{
glMatrixMode ( GL_PROJECTION ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & projection ) ) ;
#if 0
//qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
# endif
glMatrixMode ( GL_MODELVIEW ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & modelview ) ) ;
#if 0
//qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
# endif
ASSERT_MESSAGE ( realised ( ) , " render states are not realised " ) ;
// global settings that are not set in renderstates
glFrontFace ( GL_CW ) ;
glCullFace ( GL_BACK ) ;
glPolygonOffset ( - 1 , 1 ) ;
{
const GLubyte pattern [ 132 ] = {
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55 ,
0xAA , 0xAA , 0xAA , 0xAA , 0x55 , 0x55 , 0x55 , 0x55
} ;
glPolygonStipple ( pattern ) ;
}
glEnableClientState ( GL_VERTEX_ARRAY ) ;
g_vertexArray_enabled = true ;
glColorMaterial ( GL_FRONT_AND_BACK , GL_AMBIENT_AND_DIFFUSE ) ;
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
glActiveTexture ( GL_TEXTURE0 ) ;
glClientActiveTexture ( GL_TEXTURE0 ) ;
}
if ( GlobalOpenGL ( ) . ARB_shader_objects ( ) )
{
glUseProgramObjectARB ( 0 ) ;
glDisableVertexAttribArrayARB ( c_attr_TexCoord0 ) ;
glDisableVertexAttribArrayARB ( c_attr_Tangent ) ;
glDisableVertexAttribArrayARB ( c_attr_Binormal ) ;
}
if ( globalstate & RENDER_TEXTURE )
{
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
}
OpenGLState current ;
OpenGLState_constructDefault ( current ) ;
current . m_sort = OpenGLState : : eSortFirst ;
// default renderstate settings
glLineStipple ( current . m_linestipple_factor , current . m_linestipple_pattern ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
glDisable ( GL_LIGHTING ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
g_texcoordArray_enabled = false ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
g_colorArray_enabled = false ;
glDisableClientState ( GL_NORMAL_ARRAY ) ;
g_normalArray_enabled = false ;
glDisable ( GL_BLEND ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDisable ( GL_CULL_FACE ) ;
glShadeModel ( GL_FLAT ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_LINE_STIPPLE ) ;
glDisable ( GL_POLYGON_STIPPLE ) ;
glDisable ( GL_POLYGON_OFFSET_LINE ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glColor4f ( 1 , 1 , 1 , 1 ) ;
glDepthFunc ( GL_LESS ) ;
glAlphaFunc ( GL_ALWAYS , 0 ) ;
glLineWidth ( 1 ) ;
glPointSize ( 1 ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_string ( " begin rendering " ) ;
for ( OpenGLStates : : iterator i = g_state_sorted . begin ( ) ; i ! = g_state_sorted . end ( ) ; + + i )
{
( * i ) . second - > render ( current , globalstate , viewer ) ;
}
debug_string ( " end rendering " ) ;
}
void realise ( )
{
if ( - - m_unrealised = = 0 )
{
if ( lightingSupported ( ) & & lightingEnabled ( ) )
{
if ( useShaderLanguage ( ) )
{
g_bumpGLSL . create ( ) ;
g_depthFillGLSL . create ( ) ;
}
else
{
g_bumpARB . create ( ) ;
g_depthFillARB . create ( ) ;
}
}
for ( Shaders : : iterator i = m_shaders . begin ( ) ; i ! = m_shaders . end ( ) ; + + i )
{
if ( ! ( * i ) . value . empty ( ) )
{
( * i ) . value - > realise ( i - > key ) ;
}
}
}
}
void unrealise ( )
{
if ( + + m_unrealised = = 1 )
{
for ( Shaders : : iterator i = m_shaders . begin ( ) ; i ! = m_shaders . end ( ) ; + + i )
{
if ( ! ( * i ) . value . empty ( ) )
{
( * i ) . value - > unrealise ( ) ;
}
}
if ( GlobalOpenGL ( ) . contextValid & & lightingSupported ( ) & & lightingEnabled ( ) )
{
if ( useShaderLanguage ( ) )
{
g_bumpGLSL . destroy ( ) ;
g_depthFillGLSL . destroy ( ) ;
}
else
{
g_bumpARB . destroy ( ) ;
g_depthFillARB . destroy ( ) ;
}
}
}
}
bool realised ( )
{
return m_unrealised = = 0 ;
}
bool lightingEnabled ( ) const
{
return m_lightingEnabled ;
}
bool lightingSupported ( ) const
{
return m_lightingSupported ;
}
bool useShaderLanguage ( ) const
{
return m_useShaderLanguage ;
}
void setLighting ( bool supported , bool enabled )
{
bool refresh = ( m_lightingSupported & & m_lightingEnabled ) ! = ( supported & & enabled ) ;
if ( refresh )
{
unrealise ( ) ;
GlobalShaderSystem ( ) . setLightingEnabled ( supported & & enabled ) ;
}
m_lightingSupported = supported ;
m_lightingEnabled = enabled ;
if ( refresh )
{
realise ( ) ;
}
}
void extensionsInitialised ( )
{
setLighting ( GlobalOpenGL ( ) . GL_1_3 ( )
& & GlobalOpenGL ( ) . ARB_vertex_program ( )
& & GlobalOpenGL ( ) . ARB_fragment_program ( )
& & GlobalOpenGL ( ) . ARB_shader_objects ( )
& & GlobalOpenGL ( ) . ARB_vertex_shader ( )
& & GlobalOpenGL ( ) . ARB_fragment_shader ( )
& & GlobalOpenGL ( ) . ARB_shading_language_100 ( ) ,
m_lightingEnabled
) ;
if ( ! lightingSupported ( ) )
{
globalOutputStream ( ) < < " Lighting mode requires OpenGL features not supported by your graphics drivers: \n " ;
if ( ! GlobalOpenGL ( ) . GL_1_3 ( ) )
{
globalOutputStream ( ) < < " GL version 1.3 or better \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_vertex_program ( ) )
{
globalOutputStream ( ) < < " GL_ARB_vertex_program \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_fragment_program ( ) )
{
globalOutputStream ( ) < < " GL_ARB_fragment_program \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_shader_objects ( ) )
{
globalOutputStream ( ) < < " GL_ARB_shader_objects \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_vertex_shader ( ) )
{
globalOutputStream ( ) < < " GL_ARB_vertex_shader \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_fragment_shader ( ) )
{
globalOutputStream ( ) < < " GL_ARB_fragment_shader \n " ;
}
if ( ! GlobalOpenGL ( ) . ARB_shading_language_100 ( ) )
{
globalOutputStream ( ) < < " GL_ARB_shading_language_100 \n " ;
}
}
}
void setLightingEnabled ( bool enabled )
{
setLighting ( m_lightingSupported , enabled ) ;
}
// light culling
RendererLights m_lights ;
bool m_lightsChanged ;
typedef std : : map < LightCullable * , LinearLightList > LightLists ;
LightLists m_lightLists ;
const LightList & attach ( LightCullable & cullable )
{
return ( * m_lightLists . insert ( LightLists : : value_type ( & cullable , LinearLightList ( cullable , m_lights , EvaluateChangedCaller ( * this ) ) ) ) . first ) . second ;
}
void detach ( LightCullable & cullable )
{
m_lightLists . erase ( & cullable ) ;
}
void changed ( LightCullable & cullable )
{
LightLists : : iterator i = m_lightLists . find ( & cullable ) ;
ASSERT_MESSAGE ( i ! = m_lightLists . end ( ) , " cullable not attached " ) ;
( * i ) . second . lightsChanged ( ) ;
}
void attach ( RendererLight & light )
{
ASSERT_MESSAGE ( m_lights . find ( & light ) = = m_lights . end ( ) , " light could not be attached " ) ;
m_lights . insert ( & light ) ;
changed ( light ) ;
}
void detach ( RendererLight & light )
{
ASSERT_MESSAGE ( m_lights . find ( & light ) ! = m_lights . end ( ) , " light could not be detached " ) ;
m_lights . erase ( & light ) ;
changed ( light ) ;
}
void changed ( RendererLight & light )
{
m_lightsChanged = true ;
}
void evaluateChanged ( )
{
if ( m_lightsChanged )
{
m_lightsChanged = false ;
for ( LightLists : : iterator i = m_lightLists . begin ( ) ; i ! = m_lightLists . end ( ) ; + + i )
{
( * i ) . second . lightsChanged ( ) ;
}
}
}
typedef MemberCaller < OpenGLShaderCache , & OpenGLShaderCache : : evaluateChanged > EvaluateChangedCaller ;
typedef std : : set < const Renderable * > Renderables ;
Renderables m_renderables ;
mutable bool m_traverseRenderablesMutex ;
// renderables
void attachRenderable ( const Renderable & renderable )
{
ASSERT_MESSAGE ( ! m_traverseRenderablesMutex , " attaching renderable during traversal " ) ;
ASSERT_MESSAGE ( m_renderables . find ( & renderable ) = = m_renderables . end ( ) , " renderable could not be attached " ) ;
m_renderables . insert ( & renderable ) ;
}
void detachRenderable ( const Renderable & renderable )
{
ASSERT_MESSAGE ( ! m_traverseRenderablesMutex , " detaching renderable during traversal " ) ;
ASSERT_MESSAGE ( m_renderables . find ( & renderable ) ! = m_renderables . end ( ) , " renderable could not be detached " ) ;
m_renderables . erase ( & renderable ) ;
}
void forEachRenderable ( const RenderableCallback & callback ) const
{
ASSERT_MESSAGE ( ! m_traverseRenderablesMutex , " for-each during traversal " ) ;
m_traverseRenderablesMutex = true ;
2006-02-19 17:05:45 +00:00
for ( Renderables : : const_iterator i = m_renderables . begin ( ) ; i ! = m_renderables . end ( ) ; + + i )
2006-02-10 22:01:20 +00:00
{
callback ( * ( * i ) ) ;
}
m_traverseRenderablesMutex = false ;
}
} ;
static OpenGLShaderCache * g_ShaderCache ;
void ShaderCache_extensionsInitialised ( )
{
g_ShaderCache - > extensionsInitialised ( ) ;
}
void ShaderCache_setBumpEnabled ( bool enabled )
{
g_ShaderCache - > setLightingEnabled ( enabled ) ;
}
Vector3 g_DebugShaderColours [ 256 ] ;
Shader * g_defaultPointLight = 0 ;
void ShaderCache_Construct ( )
{
g_ShaderCache = new OpenGLShaderCache ;
GlobalTexturesCache ( ) . attach ( * g_ShaderCache ) ;
GlobalShaderSystem ( ) . attach ( * g_ShaderCache ) ;
if ( g_pGameDescription - > mGameType = = " doom3 " )
{
g_defaultPointLight = g_ShaderCache - > capture ( " lights/defaultPointLight " ) ;
//Shader* overbright =
g_ShaderCache - > capture ( " $OVERBRIGHT " ) ;
# if LIGHT_SHADER_DEBUG
for ( std : : size_t i = 0 ; i < 256 ; + + i )
{
g_DebugShaderColours [ i ] = Vector3 ( i / 256.0 , i / 256.0 , i / 256.0 ) ;
}
g_DebugShaderColours [ 0 ] = Vector3 ( 1 , 0 , 0 ) ;
g_DebugShaderColours [ 1 ] = Vector3 ( 1 , 0.5 , 0 ) ;
g_DebugShaderColours [ 2 ] = Vector3 ( 1 , 1 , 0 ) ;
g_DebugShaderColours [ 3 ] = Vector3 ( 0.5 , 1 , 0 ) ;
g_DebugShaderColours [ 4 ] = Vector3 ( 0 , 1 , 0 ) ;
g_DebugShaderColours [ 5 ] = Vector3 ( 0 , 1 , 0.5 ) ;
g_DebugShaderColours [ 6 ] = Vector3 ( 0 , 1 , 1 ) ;
g_DebugShaderColours [ 7 ] = Vector3 ( 0 , 0.5 , 1 ) ;
g_DebugShaderColours [ 8 ] = Vector3 ( 0 , 0 , 1 ) ;
g_DebugShaderColours [ 9 ] = Vector3 ( 0.5 , 0 , 1 ) ;
g_DebugShaderColours [ 10 ] = Vector3 ( 1 , 0 , 1 ) ;
g_DebugShaderColours [ 11 ] = Vector3 ( 1 , 0 , 0.5 ) ;
g_lightDebugShaders . reserve ( 256 ) ;
StringOutputStream buffer ( 256 ) ;
for ( std : : size_t i = 0 ; i < 256 ; + + i )
{
buffer < < " ( " < < g_DebugShaderColours [ i ] . x ( ) < < " " < < g_DebugShaderColours [ i ] . y ( ) < < " " < < g_DebugShaderColours [ i ] . z ( ) < < " ) " ;
g_lightDebugShaders . push_back ( g_ShaderCache - > capture ( buffer . c_str ( ) ) ) ;
buffer . clear ( ) ;
}
# endif
}
}
void ShaderCache_Destroy ( )
{
if ( g_pGameDescription - > mGameType = = " doom3 " )
{
g_ShaderCache - > release ( " lights/defaultPointLight " ) ;
g_ShaderCache - > release ( " $OVERBRIGHT " ) ;
g_defaultPointLight = 0 ;
# if LIGHT_SHADER_DEBUG
g_lightDebugShaders . clear ( ) ;
StringOutputStream buffer ( 256 ) ;
for ( std : : size_t i = 0 ; i < 256 ; + + i )
{
buffer < < " ( " < < g_DebugShaderColours [ i ] . x ( ) < < " " < < g_DebugShaderColours [ i ] . y ( ) < < " " < < g_DebugShaderColours [ i ] . z ( ) < < " ) " ;
g_ShaderCache - > release ( buffer . c_str ( ) ) ;
}
# endif
}
GlobalShaderSystem ( ) . detach ( * g_ShaderCache ) ;
GlobalTexturesCache ( ) . detach ( * g_ShaderCache ) ;
delete g_ShaderCache ;
}
ShaderCache * GetShaderCache ( )
{
return g_ShaderCache ;
}
inline void setTextureState ( GLint & current , const GLint & texture , GLenum textureUnit )
{
if ( texture ! = current )
{
glActiveTexture ( textureUnit ) ;
glClientActiveTexture ( textureUnit ) ;
glBindTexture ( GL_TEXTURE_2D , texture ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current = texture ;
}
}
inline void setTextureState ( GLint & current , const GLint & texture )
{
if ( texture ! = current )
{
glBindTexture ( GL_TEXTURE_2D , texture ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current = texture ;
}
}
void OpenGLState_apply ( const OpenGLState & self , OpenGLState & current , unsigned int globalstate )
{
debug_int ( " sort " , int ( self . m_sort ) ) ;
debug_int ( " texture " , self . m_texture ) ;
debug_int ( " state " , self . m_state ) ;
debug_int ( " address " , int ( std : : size_t ( & self ) ) ) ;
count_state ( ) ;
if ( self . m_state & RENDER_OVERRIDE )
{
globalstate | = RENDER_FILL | RENDER_DEPTHWRITE ;
}
const unsigned int state = self . m_state & globalstate ;
const unsigned int delta = state ^ current . m_state ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
GLProgram * program = ( state & RENDER_PROGRAM ) ! = 0 ? self . m_program : 0 ;
if ( program ! = current . m_program )
{
if ( current . m_program ! = 0 )
{
current . m_program - > disable ( ) ;
glColor4fv ( vector4_to_array ( current . m_colour ) ) ;
debug_colour ( " cleaning program " ) ;
}
current . m_program = program ;
if ( current . m_program ! = 0 )
{
current . m_program - > enable ( ) ;
}
}
if ( delta & state & RENDER_FILL )
{
//qglPolygonMode (GL_BACK, GL_LINE);
//qglPolygonMode (GL_FRONT, GL_FILL);
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_FILL )
{
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_OFFSETLINE )
{
glEnable ( GL_POLYGON_OFFSET_LINE ) ;
}
else if ( delta & ~ state & RENDER_OFFSETLINE )
{
glDisable ( GL_POLYGON_OFFSET_LINE ) ;
}
if ( delta & state & RENDER_LIGHTING )
{
glEnable ( GL_LIGHTING ) ;
glEnable ( GL_COLOR_MATERIAL ) ;
//qglEnable(GL_RESCALE_NORMAL);
glEnableClientState ( GL_NORMAL_ARRAY ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_normalArray_enabled = true ;
}
else if ( delta & ~ state & RENDER_LIGHTING )
{
glDisable ( GL_LIGHTING ) ;
glDisable ( GL_COLOR_MATERIAL ) ;
//qglDisable(GL_RESCALE_NORMAL);
glDisableClientState ( GL_NORMAL_ARRAY ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_normalArray_enabled = false ;
}
if ( delta & state & RENDER_TEXTURE )
{
GlobalOpenGL_debugAssertNoErrors ( ) ;
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
glActiveTexture ( GL_TEXTURE0 ) ;
glClientActiveTexture ( GL_TEXTURE0 ) ;
}
glEnable ( GL_TEXTURE_2D ) ;
glColor4f ( 1 , 1 , 1 , self . m_colour [ 3 ] ) ;
debug_colour ( " setting texture " ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_texcoordArray_enabled = true ;
}
else if ( delta & ~ state & RENDER_TEXTURE )
{
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
glActiveTexture ( GL_TEXTURE0 ) ;
glClientActiveTexture ( GL_TEXTURE0 ) ;
}
glDisable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_texcoordArray_enabled = false ;
}
if ( delta & state & RENDER_BLEND )
{
// FIXME: some .TGA are buggy, have a completely empty alpha channel
// if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
// so I decided using GL_DECAL instead
// if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
// this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
glEnable ( GL_BLEND ) ;
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
glActiveTexture ( GL_TEXTURE0 ) ;
}
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_DECAL ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_BLEND )
{
glDisable ( GL_BLEND ) ;
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
glActiveTexture ( GL_TEXTURE0 ) ;
}
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_CULLFACE )
{
glEnable ( GL_CULL_FACE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_CULLFACE )
{
glDisable ( GL_CULL_FACE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_SMOOTH )
{
glShadeModel ( GL_SMOOTH ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_SMOOTH )
{
glShadeModel ( GL_FLAT ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_SCALED )
{
//qglEnable(GL_RESCALE_NORMAL);
glEnable ( GL_NORMALIZE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_SCALED )
{
//qglDisable(GL_RESCALE_NORMAL);
glDisable ( GL_NORMALIZE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_DEPTHTEST )
{
glEnable ( GL_DEPTH_TEST ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_DEPTHTEST )
{
glDisable ( GL_DEPTH_TEST ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_DEPTHWRITE )
{
glDepthMask ( GL_TRUE ) ;
# if DEBUG_RENDER
GLboolean depthEnabled ;
glGetBooleanv ( GL_DEPTH_WRITEMASK , & depthEnabled ) ;
ASSERT_MESSAGE ( depthEnabled , " failed to set depth buffer mask bit " ) ;
# endif
debug_string ( " enabled depth-buffer writing " ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_DEPTHWRITE )
{
glDepthMask ( GL_FALSE ) ;
# if DEBUG_RENDER
GLboolean depthEnabled ;
glGetBooleanv ( GL_DEPTH_WRITEMASK , & depthEnabled ) ;
ASSERT_MESSAGE ( ! depthEnabled , " failed to set depth buffer mask bit " ) ;
# endif
debug_string ( " disabled depth-buffer writing " ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_COLOURWRITE )
{
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_COLOURWRITE )
{
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_ALPHATEST )
{
glEnable ( GL_ALPHA_TEST ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_ALPHATEST )
{
glDisable ( GL_ALPHA_TEST ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_COLOUR )
{
glEnableClientState ( GL_COLOR_ARRAY ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
debug_colour ( " enabling color_array " ) ;
g_colorArray_enabled = true ;
}
else if ( delta & ~ state & RENDER_COLOUR )
{
glDisableClientState ( GL_COLOR_ARRAY ) ;
glColor4fv ( vector4_to_array ( self . m_colour ) ) ;
debug_colour ( " cleaning color_array " ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
g_colorArray_enabled = false ;
}
if ( delta & state & RENDER_LINESTIPPLE )
{
glEnable ( GL_LINE_STIPPLE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_LINESTIPPLE )
{
glDisable ( GL_LINE_STIPPLE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( delta & state & RENDER_POLYGONSTIPPLE )
{
glEnable ( GL_POLYGON_STIPPLE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
else if ( delta & ~ state & RENDER_POLYGONSTIPPLE )
{
glDisable ( GL_POLYGON_STIPPLE ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( state & RENDER_DEPTHTEST & & self . m_depthfunc ! = current . m_depthfunc )
{
glDepthFunc ( self . m_depthfunc ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_depthfunc = self . m_depthfunc ;
}
if ( state & RENDER_LINESTIPPLE
& & ( self . m_linestipple_factor ! = current . m_linestipple_factor
| | self . m_linestipple_pattern ! = current . m_linestipple_pattern ) )
{
glLineStipple ( self . m_linestipple_factor , self . m_linestipple_pattern ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_linestipple_factor = self . m_linestipple_factor ;
current . m_linestipple_pattern = self . m_linestipple_pattern ;
}
if ( state & RENDER_ALPHATEST
& & ( self . m_alphafunc ! = current . m_alphafunc
| | self . m_alpharef ! = current . m_alpharef ) )
{
glAlphaFunc ( self . m_alphafunc , self . m_alpharef ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_alphafunc = self . m_alphafunc ;
current . m_alpharef = self . m_alpharef ;
}
{
GLint texture0 = 0 ;
GLint texture1 = 0 ;
GLint texture2 = 0 ;
GLint texture3 = 0 ;
GLint texture4 = 0 ;
GLint texture5 = 0 ;
GLint texture6 = 0 ;
GLint texture7 = 0 ;
//if(state & RENDER_TEXTURE) != 0)
{
texture0 = self . m_texture ;
texture1 = self . m_texture1 ;
texture2 = self . m_texture2 ;
texture3 = self . m_texture3 ;
texture4 = self . m_texture4 ;
texture5 = self . m_texture5 ;
texture6 = self . m_texture6 ;
texture7 = self . m_texture7 ;
}
if ( GlobalOpenGL ( ) . GL_1_3 ( ) )
{
setTextureState ( current . m_texture , texture0 , GL_TEXTURE0 ) ;
setTextureState ( current . m_texture1 , texture1 , GL_TEXTURE1 ) ;
setTextureState ( current . m_texture2 , texture2 , GL_TEXTURE2 ) ;
setTextureState ( current . m_texture3 , texture3 , GL_TEXTURE3 ) ;
setTextureState ( current . m_texture4 , texture4 , GL_TEXTURE4 ) ;
setTextureState ( current . m_texture5 , texture5 , GL_TEXTURE5 ) ;
setTextureState ( current . m_texture6 , texture6 , GL_TEXTURE6 ) ;
setTextureState ( current . m_texture7 , texture7 , GL_TEXTURE7 ) ;
}
else
{
setTextureState ( current . m_texture , texture0 ) ;
}
}
if ( state & RENDER_TEXTURE & & self . m_colour [ 3 ] ! = current . m_colour [ 3 ] )
{
debug_colour ( " setting alpha " ) ;
glColor4f ( 1 , 1 , 1 , self . m_colour [ 3 ] ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
if ( ! ( state & RENDER_TEXTURE )
& & ( self . m_colour [ 0 ] ! = current . m_colour [ 0 ]
| | self . m_colour [ 1 ] ! = current . m_colour [ 1 ]
| | self . m_colour [ 2 ] ! = current . m_colour [ 2 ]
| | self . m_colour [ 3 ] ! = current . m_colour [ 3 ] ) )
{
glColor4fv ( vector4_to_array ( self . m_colour ) ) ;
debug_colour ( " setting non-texture " ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
current . m_colour = self . m_colour ;
if ( state & RENDER_BLEND
& & ( self . m_blend_src ! = current . m_blend_src | | self . m_blend_dst ! = current . m_blend_dst ) )
{
glBlendFunc ( self . m_blend_src , self . m_blend_dst ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_blend_src = self . m_blend_src ;
current . m_blend_dst = self . m_blend_dst ;
}
if ( ! ( state & RENDER_FILL )
& & self . m_linewidth ! = current . m_linewidth )
{
glLineWidth ( self . m_linewidth ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_linewidth = self . m_linewidth ;
}
if ( ! ( state & RENDER_FILL )
& & self . m_pointsize ! = current . m_pointsize )
{
glPointSize ( self . m_pointsize ) ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
current . m_pointsize = self . m_pointsize ;
}
current . m_state = state ;
GlobalOpenGL_debugAssertNoErrors ( ) ;
}
void Renderables_flush ( OpenGLStateBucket : : Renderables & renderables , OpenGLState & current , unsigned int globalstate , const Vector3 & viewer )
{
const Matrix4 * transform = 0 ;
glPushMatrix ( ) ;
for ( OpenGLStateBucket : : Renderables : : const_iterator i = renderables . begin ( ) ; i ! = renderables . end ( ) ; + + i )
{
//qglLoadMatrixf(i->m_transform);
if ( ! transform | | ( transform ! = ( * i ) . m_transform & & ! matrix4_affine_equal ( * transform , * ( * i ) . m_transform ) ) )
{
count_transform ( ) ;
transform = ( * i ) . m_transform ;
glPopMatrix ( ) ;
glPushMatrix ( ) ;
glMultMatrixf ( reinterpret_cast < const float * > ( transform ) ) ;
glFrontFace ( ( ( current . m_state & RENDER_CULLFACE ) ! = 0 & & matrix4_handedness ( * transform ) = = MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW ) ;
}
count_prim ( ) ;
if ( current . m_program ! = 0 & & ( * i ) . m_light ! = 0 )
{
const IShader & lightShader = static_cast < OpenGLShader * > ( ( * i ) . m_light - > getShader ( ) ) - > getShader ( ) ;
if ( lightShader . firstLayer ( ) ! = 0 )
{
GLuint attenuation_xy = lightShader . firstLayer ( ) - > texture ( ) - > texture_number ;
GLuint attenuation_z = lightShader . lightFalloffImage ( ) ! = 0
? lightShader . lightFalloffImage ( ) - > texture_number
: static_cast < OpenGLShader * > ( g_defaultPointLight ) - > getShader ( ) . lightFalloffImage ( ) - > texture_number ;
setTextureState ( current . m_texture3 , attenuation_xy , GL_TEXTURE3 ) ;
glActiveTexture ( GL_TEXTURE3 ) ;
glBindTexture ( GL_TEXTURE_2D , attenuation_xy ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
setTextureState ( current . m_texture4 , attenuation_z , GL_TEXTURE4 ) ;
glActiveTexture ( GL_TEXTURE4 ) ;
glBindTexture ( GL_TEXTURE_2D , attenuation_z ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
AABB lightBounds ( ( * i ) . m_light - > aabb ( ) ) ;
Matrix4 world2light ( g_matrix4_identity ) ;
if ( ( * i ) . m_light - > isProjected ( ) )
{
world2light = ( * i ) . m_light - > projection ( ) ;
matrix4_multiply_by_matrix4 ( world2light , matrix4_transposed ( ( * i ) . m_light - > rotation ( ) ) ) ;
matrix4_translate_by_vec3 ( world2light , vector3_negated ( lightBounds . origin ) ) ; // world->lightBounds
}
if ( ! ( * i ) . m_light - > isProjected ( ) )
{
matrix4_translate_by_vec3 ( world2light , Vector3 ( 0.5f , 0.5f , 0.5f ) ) ;
matrix4_scale_by_vec3 ( world2light , Vector3 ( 0.5f , 0.5f , 0.5f ) ) ;
matrix4_scale_by_vec3 ( world2light , Vector3 ( 1.0f / lightBounds . extents . x ( ) , 1.0f / lightBounds . extents . y ( ) , 1.0f / lightBounds . extents . z ( ) ) ) ;
matrix4_multiply_by_matrix4 ( world2light , matrix4_transposed ( ( * i ) . m_light - > rotation ( ) ) ) ;
matrix4_translate_by_vec3 ( world2light , vector3_negated ( lightBounds . origin ) ) ; // world->lightBounds
}
current . m_program - > setParameters ( viewer , * ( * i ) . m_transform , lightBounds . origin + ( * i ) . m_light - > offset ( ) , ( * i ) . m_light - > colour ( ) , world2light ) ;
debug_string ( " set lightBounds parameters " ) ;
}
}
( * i ) . m_renderable - > render ( current . m_state ) ;
}
glPopMatrix ( ) ;
renderables . clear ( ) ;
}
void OpenGLStateBucket : : render ( OpenGLState & current , unsigned int globalstate , const Vector3 & viewer )
{
if ( ( globalstate & m_state . m_state & RENDER_SCREEN ) ! = 0 )
{
OpenGLState_apply ( m_state , current , globalstate ) ;
debug_colour ( " screen fill " ) ;
glMatrixMode ( GL_PROJECTION ) ;
glPushMatrix ( ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & g_matrix4_identity ) ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPushMatrix ( ) ;
glLoadMatrixf ( reinterpret_cast < const float * > ( & g_matrix4_identity ) ) ;
glBegin ( GL_QUADS ) ;
glVertex3f ( - 1 , - 1 , 0 ) ;
glVertex3f ( 1 , - 1 , 0 ) ;
glVertex3f ( 1 , 1 , 0 ) ;
glVertex3f ( - 1 , 1 , 0 ) ;
glEnd ( ) ;
glMatrixMode ( GL_PROJECTION ) ;
glPopMatrix ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPopMatrix ( ) ;
}
else if ( ! m_renderables . empty ( ) )
{
OpenGLState_apply ( m_state , current , globalstate ) ;
Renderables_flush ( m_renderables , current , globalstate , viewer ) ;
}
}
inline GLenum convertBlendFactor ( BlendFactor factor )
{
switch ( factor )
{
case BLEND_ZERO :
return GL_ZERO ;
case BLEND_ONE :
return GL_ONE ;
case BLEND_SRC_COLOUR :
return GL_SRC_COLOR ;
case BLEND_ONE_MINUS_SRC_COLOUR :
return GL_ONE_MINUS_SRC_COLOR ;
case BLEND_SRC_ALPHA :
return GL_SRC_ALPHA ;
case BLEND_ONE_MINUS_SRC_ALPHA :
return GL_ONE_MINUS_SRC_ALPHA ;
case BLEND_DST_COLOUR :
return GL_DST_COLOR ;
case BLEND_ONE_MINUS_DST_COLOUR :
return GL_ONE_MINUS_DST_COLOR ;
case BLEND_DST_ALPHA :
return GL_DST_ALPHA ;
case BLEND_ONE_MINUS_DST_ALPHA :
return GL_ONE_MINUS_DST_ALPHA ;
case BLEND_SRC_ALPHA_SATURATE :
return GL_SRC_ALPHA_SATURATE ;
}
return GL_ZERO ;
}
/// \todo Define special-case shaders in a data file.
void OpenGLShader : : construct ( const char * name )
{
OpenGLState & state = appendDefaultPass ( ) ;
switch ( name [ 0 ] )
{
case ' ( ' :
sscanf ( name , " (%g %g %g) " , & state . m_colour [ 0 ] , & state . m_colour [ 1 ] , & state . m_colour [ 2 ] ) ;
state . m_colour [ 3 ] = 1.0f ;
state . m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFullbright ;
break ;
case ' [ ' :
sscanf ( name , " [%g %g %g] " , & state . m_colour [ 0 ] , & state . m_colour [ 1 ] , & state . m_colour [ 2 ] ) ;
state . m_colour [ 3 ] = 0.5f ;
state . m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_BLEND ;
state . m_sort = OpenGLState : : eSortTranslucent ;
break ;
case ' < ' :
sscanf ( name , " <%g %g %g> " , & state . m_colour [ 0 ] , & state . m_colour [ 1 ] , & state . m_colour [ 2 ] ) ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFullbright ;
state . m_depthfunc = GL_LESS ;
state . m_linewidth = 1 ;
state . m_pointsize = 1 ;
break ;
case ' $ ' :
if ( string_equal ( name + 1 , " POINT " ) )
{
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortControlFirst ;
state . m_pointsize = 4 ;
}
else if ( string_equal ( name + 1 , " SELPOINT " ) )
{
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortControlFirst + 1 ;
state . m_pointsize = 4 ;
}
else if ( string_equal ( name + 1 , " BIGPOINT " ) )
{
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortControlFirst ;
state . m_pointsize = 6 ;
}
else if ( string_equal ( name + 1 , " PIVOT " ) )
{
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortGUI1 ;
state . m_linewidth = 2 ;
state . m_depthfunc = GL_LEQUAL ;
OpenGLState & hiddenLine = appendDefaultPass ( ) ;
hiddenLine . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE ;
hiddenLine . m_sort = OpenGLState : : eSortGUI0 ;
hiddenLine . m_linewidth = 2 ;
hiddenLine . m_depthfunc = GL_GREATER ;
}
else if ( string_equal ( name + 1 , " LATTICE " ) )
{
state . m_colour [ 0 ] = 1 ;
state . m_colour [ 1 ] = 0.5 ;
state . m_colour [ 2 ] = 0 ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortControlFirst ;
}
else if ( string_equal ( name + 1 , " WIREFRAME " ) )
{
state . m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFullbright ;
}
else if ( string_equal ( name + 1 , " CAM_HIGHLIGHT " ) )
{
state . m_colour [ 0 ] = 1 ;
state . m_colour [ 1 ] = 0 ;
state . m_colour [ 2 ] = 0 ;
state . m_colour [ 3 ] = 0.3f ;
state . m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortHighlight ;
state . m_depthfunc = GL_LEQUAL ;
}
else if ( string_equal ( name + 1 , " CAM_OVERLAY " ) )
{
#if 0
state . m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortOverlayFirst ;
# else
state . m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE ;
state . m_sort = OpenGLState : : eSortOverlayFirst + 1 ;
state . m_depthfunc = GL_LEQUAL ;
OpenGLState & hiddenLine = appendDefaultPass ( ) ;
hiddenLine . m_colour [ 0 ] = 0.75 ;
hiddenLine . m_colour [ 1 ] = 0.75 ;
hiddenLine . m_colour [ 2 ] = 0.75 ;
hiddenLine . m_colour [ 3 ] = 1 ;
hiddenLine . m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE | RENDER_LINESTIPPLE ;
hiddenLine . m_sort = OpenGLState : : eSortOverlayFirst ;
hiddenLine . m_depthfunc = GL_GREATER ;
hiddenLine . m_linestipple_factor = 2 ;
# endif
}
else if ( string_equal ( name + 1 , " XY_OVERLAY " ) )
{
state . m_colour [ 0 ] = g_xywindow_globals . color_selbrushes [ 0 ] ;
state . m_colour [ 1 ] = g_xywindow_globals . color_selbrushes [ 1 ] ;
state . m_colour [ 2 ] = g_xywindow_globals . color_selbrushes [ 2 ] ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE ;
state . m_sort = OpenGLState : : eSortOverlayFirst ;
state . m_linewidth = 2 ;
state . m_linestipple_factor = 3 ;
}
else if ( string_equal ( name + 1 , " DEBUG_CLIPPED " ) )
{
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortLast ;
}
else if ( string_equal ( name + 1 , " POINTFILE " ) )
{
state . m_colour [ 0 ] = 1 ;
state . m_colour [ 1 ] = 0 ;
state . m_colour [ 2 ] = 0 ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFullbright ;
state . m_linewidth = 4 ;
}
else if ( string_equal ( name + 1 , " LIGHT_SPHERE " ) )
{
state . m_colour [ 0 ] = .15f * .95f ;
state . m_colour [ 1 ] = .15f * .95f ;
state . m_colour [ 2 ] = .15f * .95f ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_blend_src = GL_ONE ;
state . m_blend_dst = GL_ONE ;
state . m_sort = OpenGLState : : eSortTranslucent ;
}
else if ( string_equal ( name + 1 , " Q3MAP2_LIGHT_SPHERE " ) )
{
state . m_colour [ 0 ] = .05f ;
state . m_colour [ 1 ] = .05f ;
state . m_colour [ 2 ] = .05f ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL ;
state . m_blend_src = GL_ONE ;
state . m_blend_dst = GL_ONE ;
state . m_sort = OpenGLState : : eSortTranslucent ;
}
else if ( string_equal ( name + 1 , " WIRE_OVERLAY " ) )
{
#if 0
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE ;
state . m_sort = OpenGLState : : eSortOverlayFirst ;
# else
state . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE ;
state . m_sort = OpenGLState : : eSortGUI1 ;
state . m_depthfunc = GL_LEQUAL ;
OpenGLState & hiddenLine = appendDefaultPass ( ) ;
hiddenLine . m_state = RENDER_COLOUR | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_LINESTIPPLE ;
hiddenLine . m_sort = OpenGLState : : eSortGUI0 ;
hiddenLine . m_depthfunc = GL_GREATER ;
# endif
}
else if ( string_equal ( name + 1 , " FLATSHADE_OVERLAY " ) )
{
state . m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOUR | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE ;
state . m_sort = OpenGLState : : eSortGUI1 ;
state . m_depthfunc = GL_LEQUAL ;
OpenGLState & hiddenLine = appendDefaultPass ( ) ;
hiddenLine . m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOUR | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_POLYGONSTIPPLE ;
hiddenLine . m_sort = OpenGLState : : eSortGUI0 ;
hiddenLine . m_depthfunc = GL_GREATER ;
}
else if ( string_equal ( name + 1 , " CLIPPER_OVERLAY " ) )
{
state . m_colour [ 0 ] = g_xywindow_globals . color_clipper [ 0 ] ;
state . m_colour [ 1 ] = g_xywindow_globals . color_clipper [ 1 ] ;
state . m_colour [ 2 ] = g_xywindow_globals . color_clipper [ 2 ] ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE ;
state . m_sort = OpenGLState : : eSortOverlayFirst ;
}
else if ( string_equal ( name + 1 , " OVERBRIGHT " ) )
{
const float lightScale = 2 ;
state . m_colour [ 0 ] = lightScale * 0.5f ;
state . m_colour [ 1 ] = lightScale * 0.5f ;
state . m_colour [ 2 ] = lightScale * 0.5f ;
state . m_colour [ 3 ] = 0.5 ;
state . m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN ;
state . m_sort = OpenGLState : : eSortOverbrighten ;
state . m_blend_src = GL_DST_COLOR ;
state . m_blend_dst = GL_SRC_COLOR ;
}
else
{
// default to something recognisable.. =)
ERROR_MESSAGE ( " hardcoded renderstate not found " ) ;
state . m_colour [ 0 ] = 1 ;
state . m_colour [ 1 ] = 0 ;
state . m_colour [ 2 ] = 1 ;
state . m_colour [ 3 ] = 1 ;
state . m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFirst ;
}
break ;
default :
// construction from IShader
m_shader = QERApp_Shader_ForName ( name ) ;
if ( g_ShaderCache - > lightingSupported ( ) & & g_ShaderCache - > lightingEnabled ( ) & & m_shader - > getBump ( ) ! = 0 & & m_shader - > getBump ( ) - > texture_number ! = 0 ) // is a bump shader
{
state . m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM ;
state . m_colour [ 0 ] = 0 ;
state . m_colour [ 1 ] = 0 ;
state . m_colour [ 2 ] = 0 ;
state . m_colour [ 3 ] = 1 ;
state . m_sort = OpenGLState : : eSortOpaque ;
if ( g_ShaderCache - > useShaderLanguage ( ) )
{
state . m_program = & g_depthFillGLSL ;
}
else
{
state . m_program = & g_depthFillARB ;
}
OpenGLState & bumpPass = appendDefaultPass ( ) ;
bumpPass . m_texture = m_shader - > getDiffuse ( ) - > texture_number ;
bumpPass . m_texture1 = m_shader - > getBump ( ) - > texture_number ;
bumpPass . m_texture2 = m_shader - > getSpecular ( ) - > texture_number ;
bumpPass . m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM ;
if ( g_ShaderCache - > useShaderLanguage ( ) )
{
bumpPass . m_state | = RENDER_LIGHTING ;
bumpPass . m_program = & g_bumpGLSL ;
}
else
{
bumpPass . m_program = & g_bumpARB ;
}
bumpPass . m_depthfunc = GL_LEQUAL ;
bumpPass . m_sort = OpenGLState : : eSortMultiFirst ;
bumpPass . m_blend_src = GL_ONE ;
bumpPass . m_blend_dst = GL_ONE ;
}
else
{
state . m_texture = m_shader - > getTexture ( ) - > texture_number ;
state . m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH ;
if ( ( m_shader - > getFlags ( ) & QER_CULL ) ! = 0 )
{
if ( m_shader - > getCull ( ) = = IShader : : eCullBack )
{
state . m_state | = RENDER_CULLFACE ;
}
}
else
{
state . m_state | = RENDER_CULLFACE ;
}
if ( ( m_shader - > getFlags ( ) & QER_ALPHATEST ) ! = 0 )
{
state . m_state | = RENDER_ALPHATEST ;
IShader : : EAlphaFunc alphafunc ;
m_shader - > getAlphaFunc ( & alphafunc , & state . m_alpharef ) ;
switch ( alphafunc )
{
case IShader : : eAlways :
state . m_alphafunc = GL_ALWAYS ;
case IShader : : eEqual :
state . m_alphafunc = GL_EQUAL ;
case IShader : : eLess :
state . m_alphafunc = GL_LESS ;
case IShader : : eGreater :
state . m_alphafunc = GL_GREATER ;
case IShader : : eLEqual :
state . m_alphafunc = GL_LEQUAL ;
case IShader : : eGEqual :
state . m_alphafunc = GL_GEQUAL ;
}
}
reinterpret_cast < Vector3 & > ( state . m_colour ) = m_shader - > getTexture ( ) - > color ;
state . m_colour [ 3 ] = 1.0f ;
if ( ( m_shader - > getFlags ( ) & QER_TRANS ) ! = 0 )
{
state . m_state | = RENDER_BLEND ;
state . m_colour [ 3 ] = m_shader - > getTrans ( ) ;
state . m_sort = OpenGLState : : eSortTranslucent ;
BlendFunc blendFunc = m_shader - > getBlendFunc ( ) ;
state . m_blend_src = convertBlendFactor ( blendFunc . m_src ) ;
state . m_blend_dst = convertBlendFactor ( blendFunc . m_dst ) ;
if ( state . m_blend_src = = GL_SRC_ALPHA | | state . m_blend_dst = = GL_SRC_ALPHA )
{
state . m_state | = RENDER_DEPTHWRITE ;
}
}
else
{
state . m_state | = RENDER_DEPTHWRITE ;
state . m_sort = OpenGLState : : eSortFullbright ;
}
}
}
}
# include "modulesystem/singletonmodule.h"
# include "modulesystem/moduleregistry.h"
class ShaderCacheDependencies : public GlobalShadersModuleRef , public GlobalTexturesModuleRef
{
public :
ShaderCacheDependencies ( ) :
GlobalShadersModuleRef ( GlobalRadiant ( ) . getRequiredGameDescriptionKeyValue ( " shaders " ) )
{
}
} ;
class ShaderCacheAPI
{
ShaderCache * m_shaderCache ;
public :
typedef ShaderCache Type ;
STRING_CONSTANT ( Name , " * " ) ;
ShaderCacheAPI ( )
{
ShaderCache_Construct ( ) ;
m_shaderCache = GetShaderCache ( ) ;
}
~ ShaderCacheAPI ( )
{
ShaderCache_Destroy ( ) ;
}
ShaderCache * getTable ( )
{
return m_shaderCache ;
}
} ;
typedef SingletonModule < ShaderCacheAPI , ShaderCacheDependencies > ShaderCacheModule ;
typedef Static < ShaderCacheModule > StaticShaderCacheModule ;
StaticRegisterModule staticRegisterShaderCache ( StaticShaderCacheModule : : instance ( ) ) ;