2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "renderstate.h"
24 #include "debugging/debugging.h"
29 #include "itextures.h"
31 #include "iglrender.h"
32 #include "renderable.h"
33 #include "qerplugin.h"
40 #include "math/matrix.h"
41 #include "math/aabb.h"
42 #include "generic/callback.h"
43 #include "texturelib.h"
44 #include "string/string.h"
45 #include "container/hashfunc.h"
46 #include "container/cache.h"
47 #include "generic/reference.h"
48 #include "moduleobservers.h"
49 #include "stream/filestream.h"
50 #include "stream/stringstream.h"
52 #include "preferences.h"
57 #define DEBUG_RENDER 0
59 inline void debug_string( const char* string ){
61 globalOutputStream() << string << "\n";
65 inline void debug_int( const char* comment, int i ){
67 globalOutputStream() << comment << " " << i << "\n";
71 inline void debug_colour( const char* comment ){
74 glGetFloatv( GL_CURRENT_COLOR, reinterpret_cast<float*>( &v ) );
75 globalOutputStream() << comment << " colour: "
80 if ( glIsEnabled( GL_COLOR_ARRAY ) ) {
81 globalOutputStream() << " ARRAY";
83 if ( glIsEnabled( GL_COLOR_MATERIAL ) ) {
84 globalOutputStream() << " MATERIAL";
86 globalOutputStream() << "\n";
92 StringOutputStream g_renderer_stats;
93 std::size_t g_count_prims;
94 std::size_t g_count_states;
95 std::size_t g_count_transforms;
98 inline void count_prim(){
102 inline void count_state(){
106 inline void count_transform(){
107 ++g_count_transforms;
110 void Renderer_ResetStats(){
113 g_count_transforms = 0;
117 const char* Renderer_GetStats(){
118 g_renderer_stats.clear();
119 g_renderer_stats << "prims: " << Unsigned( g_count_prims )
120 << " | states: " << Unsigned( g_count_states )
121 << " | transforms: " << Unsigned( g_count_transforms )
122 << " | msec: " << g_timer.elapsed_msec();
123 return g_renderer_stats.c_str();
127 void printShaderLog( GLhandleARB object ){
128 GLint log_length = 0;
129 glGetObjectParameterivARB( object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length );
131 Array<char> log( log_length );
132 glGetInfoLogARB( object, log_length, &log_length, log.data() );
134 globalErrorStream() << StringRange( log.begin(), log.begin() + log_length ) << "\n";
137 void createShader( GLhandleARB program, const char* filename, GLenum type ){
138 GLhandleARB shader = glCreateShaderObjectARB( type );
139 GlobalOpenGL_debugAssertNoErrors();
143 std::size_t size = file_size( filename );
144 FileInputStream file( filename );
145 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
146 Array<GLcharARB> buffer( size );
147 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
149 const GLcharARB* string = buffer.data();
150 GLint length = GLint( size );
151 glShaderSourceARB( shader, 1, &string, &length );
156 glCompileShaderARB( shader );
159 glGetObjectParameterivARB( shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled );
162 printShaderLog( shader );
165 ASSERT_MESSAGE( compiled, "shader compile failed: " << makeQuoted( filename ) );
169 glAttachObjectARB( program, shader );
171 glDeleteObjectARB( shader );
173 GlobalOpenGL_debugAssertNoErrors();
176 void GLSLProgram_link( GLhandleARB program ){
177 glLinkProgramARB( program );
179 GLint linked = false;
180 glGetObjectParameterivARB( program, GL_OBJECT_LINK_STATUS_ARB, &linked );
183 printShaderLog( program );
186 ASSERT_MESSAGE( linked, "program link failed" );
189 void GLSLProgram_validate( GLhandleARB program ){
190 glValidateProgramARB( program );
192 GLint validated = false;
193 glGetObjectParameterivARB( program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated );
196 printShaderLog( program );
199 ASSERT_MESSAGE( validated, "program validation failed" );
202 bool g_bumpGLSLPass_enabled = false;
203 bool g_depthfillPass_enabled = false;
205 class GLSLBumpProgram : public GLProgram
208 GLhandleARB m_program;
209 qtexture_t* m_light_attenuation_xy;
210 qtexture_t* m_light_attenuation_z;
212 GLint u_light_origin;
215 GLint u_specular_exponent;
217 GLSLBumpProgram() : m_program( 0 ), m_light_attenuation_xy( 0 ), m_light_attenuation_z( 0 ){
222 m_program = glCreateProgramObjectARB();
226 StringOutputStream filename( 256 );
227 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_vp.glsl";
228 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
230 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_fp.glsl";
231 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
234 GLSLProgram_link( m_program );
235 GLSLProgram_validate( m_program );
237 glUseProgramObjectARB( m_program );
239 glBindAttribLocationARB( m_program, c_attr_TexCoord0, "attr_TexCoord0" );
240 glBindAttribLocationARB( m_program, c_attr_Tangent, "attr_Tangent" );
241 glBindAttribLocationARB( m_program, c_attr_Binormal, "attr_Binormal" );
243 glUniform1iARB( glGetUniformLocationARB( m_program, "u_diffusemap" ), 0 );
244 glUniform1iARB( glGetUniformLocationARB( m_program, "u_bumpmap" ), 1 );
245 glUniform1iARB( glGetUniformLocationARB( m_program, "u_specularmap" ), 2 );
246 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_xy" ), 3 );
247 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_z" ), 4 );
249 u_view_origin = glGetUniformLocationARB( m_program, "u_view_origin" );
250 u_light_origin = glGetUniformLocationARB( m_program, "u_light_origin" );
251 u_light_color = glGetUniformLocationARB( m_program, "u_light_color" );
252 u_bump_scale = glGetUniformLocationARB( m_program, "u_bump_scale" );
253 u_specular_exponent = glGetUniformLocationARB( m_program, "u_specular_exponent" );
255 glUseProgramObjectARB( 0 );
257 GlobalOpenGL_debugAssertNoErrors();
261 glDeleteObjectARB( m_program );
266 glUseProgramObjectARB( m_program );
268 glEnableVertexAttribArrayARB( c_attr_TexCoord0 );
269 glEnableVertexAttribArrayARB( c_attr_Tangent );
270 glEnableVertexAttribArrayARB( c_attr_Binormal );
272 GlobalOpenGL_debugAssertNoErrors();
274 debug_string( "enable bump" );
275 g_bumpGLSLPass_enabled = true;
279 glUseProgramObjectARB( 0 );
281 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
282 glDisableVertexAttribArrayARB( c_attr_Tangent );
283 glDisableVertexAttribArrayARB( c_attr_Binormal );
285 GlobalOpenGL_debugAssertNoErrors();
287 debug_string( "disable bump" );
288 g_bumpGLSLPass_enabled = false;
291 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
292 Matrix4 world2local( localToWorld );
293 matrix4_affine_invert( world2local );
295 Vector3 localLight( origin );
296 matrix4_transform_point( world2local, localLight );
298 Vector3 localViewer( viewer );
299 matrix4_transform_point( world2local, localViewer );
301 Matrix4 local2light( world2light );
302 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
304 glUniform3fARB( u_view_origin, localViewer.x(), localViewer.y(), localViewer.z() );
305 glUniform3fARB( u_light_origin, localLight.x(), localLight.y(), localLight.z() );
306 glUniform3fARB( u_light_color, colour.x(), colour.y(), colour.z() );
307 glUniform1fARB( u_bump_scale, 1.0 );
308 glUniform1fARB( u_specular_exponent, 32.0 );
310 glActiveTexture( GL_TEXTURE3 );
311 glClientActiveTexture( GL_TEXTURE3 );
313 glMatrixMode( GL_TEXTURE );
314 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
315 glMatrixMode( GL_MODELVIEW );
317 GlobalOpenGL_debugAssertNoErrors();
321 GLSLBumpProgram g_bumpGLSL;
324 class GLSLDepthFillProgram : public GLProgram
327 GLhandleARB m_program;
331 m_program = glCreateProgramObjectARB();
335 StringOutputStream filename( 256 );
336 filename << GlobalRadiant().getDataPath() << "gl/zfill_vp.glsl";
337 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
339 filename << GlobalRadiant().getDataPath() << "gl/zfill_fp.glsl";
340 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
343 GLSLProgram_link( m_program );
344 GLSLProgram_validate( m_program );
346 GlobalOpenGL_debugAssertNoErrors();
350 glDeleteObjectARB( m_program );
355 glUseProgramObjectARB( m_program );
356 GlobalOpenGL_debugAssertNoErrors();
357 debug_string( "enable depthfill" );
358 g_depthfillPass_enabled = true;
362 glUseProgramObjectARB( 0 );
363 GlobalOpenGL_debugAssertNoErrors();
364 debug_string( "disable depthfill" );
365 g_depthfillPass_enabled = false;
367 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
371 GLSLDepthFillProgram g_depthFillGLSL;
376 void createProgram( const char* filename, GLenum type ){
377 std::size_t size = file_size( filename );
378 FileInputStream file( filename );
379 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
380 Array<GLcharARB> buffer( size );
381 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
383 glProgramStringARB( type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei( size ), buffer.data() );
385 if ( GL_INVALID_OPERATION == glGetError() ) {
387 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
388 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_ARB );
390 globalErrorStream() << reinterpret_cast<const char*>( filename ) << ":" << errPos << "\n" << reinterpret_cast<const char*>( errString );
392 ERROR_MESSAGE( "error in gl program" );
396 class ARBBumpProgram : public GLProgram
399 GLuint m_vertex_program;
400 GLuint m_fragment_program;
403 glEnable( GL_VERTEX_PROGRAM_ARB );
404 glEnable( GL_FRAGMENT_PROGRAM_ARB );
407 glGenProgramsARB( 1, &m_vertex_program );
408 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
409 StringOutputStream filename( 256 );
410 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_vp.glp";
411 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
413 glGenProgramsARB( 1, &m_fragment_program );
414 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
416 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_fp.glp";
417 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
420 glDisable( GL_VERTEX_PROGRAM_ARB );
421 glDisable( GL_FRAGMENT_PROGRAM_ARB );
423 GlobalOpenGL_debugAssertNoErrors();
427 glDeleteProgramsARB( 1, &m_vertex_program );
428 glDeleteProgramsARB( 1, &m_fragment_program );
429 GlobalOpenGL_debugAssertNoErrors();
433 glEnable( GL_VERTEX_PROGRAM_ARB );
434 glEnable( GL_FRAGMENT_PROGRAM_ARB );
435 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
436 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
438 glEnableVertexAttribArrayARB( 8 );
439 glEnableVertexAttribArrayARB( 9 );
440 glEnableVertexAttribArrayARB( 10 );
441 glEnableVertexAttribArrayARB( 11 );
443 GlobalOpenGL_debugAssertNoErrors();
447 glDisable( GL_VERTEX_PROGRAM_ARB );
448 glDisable( GL_FRAGMENT_PROGRAM_ARB );
450 glDisableVertexAttribArrayARB( 8 );
451 glDisableVertexAttribArrayARB( 9 );
452 glDisableVertexAttribArrayARB( 10 );
453 glDisableVertexAttribArrayARB( 11 );
455 GlobalOpenGL_debugAssertNoErrors();
458 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
459 Matrix4 world2local( localToWorld );
460 matrix4_affine_invert( world2local );
462 Vector3 localLight( origin );
463 matrix4_transform_point( world2local, localLight );
465 Vector3 localViewer( viewer );
466 matrix4_transform_point( world2local, localViewer );
468 Matrix4 local2light( world2light );
469 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
472 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0 );
475 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1 );
478 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0 );
481 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0 );
484 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0 );
487 glActiveTexture( GL_TEXTURE3 );
488 glClientActiveTexture( GL_TEXTURE3 );
490 glMatrixMode( GL_TEXTURE );
491 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
492 glMatrixMode( GL_MODELVIEW );
494 GlobalOpenGL_debugAssertNoErrors();
498 class ARBDepthFillProgram : public GLProgram
501 GLuint m_vertex_program;
502 GLuint m_fragment_program;
505 glEnable( GL_VERTEX_PROGRAM_ARB );
506 glEnable( GL_FRAGMENT_PROGRAM_ARB );
509 glGenProgramsARB( 1, &m_vertex_program );
510 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
511 StringOutputStream filename( 256 );
512 filename << GlobalRadiant().getDataPath() << "gl/zfill_vp.glp";
513 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
515 glGenProgramsARB( 1, &m_fragment_program );
516 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
518 filename << GlobalRadiant().getDataPath() << "gl/zfill_fp.glp";
519 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
522 glDisable( GL_VERTEX_PROGRAM_ARB );
523 glDisable( GL_FRAGMENT_PROGRAM_ARB );
525 GlobalOpenGL_debugAssertNoErrors();
529 glDeleteProgramsARB( 1, &m_vertex_program );
530 glDeleteProgramsARB( 1, &m_fragment_program );
531 GlobalOpenGL_debugAssertNoErrors();
535 glEnable( GL_VERTEX_PROGRAM_ARB );
536 glEnable( GL_FRAGMENT_PROGRAM_ARB );
537 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
538 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
540 GlobalOpenGL_debugAssertNoErrors();
544 glDisable( GL_VERTEX_PROGRAM_ARB );
545 glDisable( GL_FRAGMENT_PROGRAM_ARB );
547 GlobalOpenGL_debugAssertNoErrors();
550 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
554 ARBBumpProgram g_bumpARB;
555 ARBDepthFillProgram g_depthFillARB;
559 // NV20 path (unfinished)
561 void createProgram( GLint program, const char* filename, GLenum type ){
562 std::size_t size = file_size( filename );
563 FileInputStream file( filename );
564 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
565 Array<GLubyte> buffer( size );
566 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
568 glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
570 if ( GL_INVALID_OPERATION == glGetError() ) {
572 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
573 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
575 globalErrorStream() << filename << ":" << errPos << "\n" << errString;
577 ERROR_MESSAGE( "error in gl program" );
581 GLuint m_vertex_program;
582 GLuint m_fragment_program;
583 qtexture_t* g_cube = 0;
584 qtexture_t* g_specular_lookup = 0;
585 qtexture_t* g_attenuation_xy = 0;
586 qtexture_t* g_attenuation_z = 0;
588 void createVertexProgram(){
590 glGenProgramsNV( 1, &m_vertex_program );
591 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
592 StringOutputStream filename( 256 );
593 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_vp.nv30";
594 createProgram( m_vertex_program, filename.c_str(), GL_VERTEX_PROGRAM_NV );
596 glGenProgramsNV( 1, &m_fragment_program );
597 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
599 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_fp.nv30";
600 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
603 g_cube = GlobalTexturesCache().capture( "generated/cube" );
604 g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
606 g_attenuation_xy = GlobalTexturesCache().capture( "lights/squarelight1" );
607 glActiveTexture( GL_TEXTURE0 );
608 glBindTexture( GL_TEXTURE_2D, g_attenuation_xy->texture_number );
609 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
610 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
612 g_attenuation_z = GlobalTexturesCache().capture( "lights/squarelight1a" );
613 glActiveTexture( GL_TEXTURE0 );
614 glBindTexture( GL_TEXTURE_2D, g_attenuation_z->texture_number );
615 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
616 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
618 GlobalOpenGL_debugAssertNoErrors();
621 void destroyVertexProgram(){
622 glDeleteProgramsNV( 1, &m_vertex_program );
623 glDeleteProgramsNV( 1, &m_fragment_program );
624 GlobalOpenGL_debugAssertNoErrors();
626 GlobalTexturesCache().release( g_cube );
627 GlobalTexturesCache().release( g_specular_lookup );
628 GlobalTexturesCache().release( g_attenuation_xy );
629 GlobalTexturesCache().release( g_attenuation_z );
632 bool g_vertexProgram_enabled = false;
634 void enableVertexProgram(){
635 //set up the register combiners
636 //two general combiners
637 glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
639 //combiner 0 does tex0+tex1 -> spare0
640 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB,
641 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
642 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
643 GL_UNSIGNED_INVERT_NV, GL_RGB );
644 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB,
645 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
646 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
647 GL_UNSIGNED_INVERT_NV, GL_RGB );
648 glCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV,
649 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
651 //combiner 1 does tex2 dot tex3 -> spare1
652 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE2_ARB,
653 GL_EXPAND_NORMAL_NV, GL_RGB );
654 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE3_ARB,
655 GL_EXPAND_NORMAL_NV, GL_RGB );
656 glCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
657 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
661 //final combiner outputs (1-spare0)*constant color 0*spare1
662 //do constant color 0*spare1 in the EF multiplier
663 glFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
664 glFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
666 //now do (1-spare0)*EF
667 glFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
668 glFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
669 glFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
670 glFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
672 glEnable( GL_VERTEX_PROGRAM_NV );
673 glEnable( GL_REGISTER_COMBINERS_NV );
674 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
675 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
677 glActiveTexture( GL_TEXTURE0 );
678 glEnable( GL_TEXTURE_2D );
679 glActiveTexture( GL_TEXTURE1 );
680 glEnable( GL_TEXTURE_1D );
681 glActiveTexture( GL_TEXTURE2 );
682 glEnable( GL_TEXTURE_2D );
683 glActiveTexture( GL_TEXTURE3 );
684 glEnable( GL_TEXTURE_2D );
686 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
687 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
688 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
689 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
691 GlobalOpenGL_debugAssertNoErrors();
692 g_vertexProgram_enabled = true;
695 void disableVertexProgram(){
696 glDisable( GL_VERTEX_PROGRAM_NV );
697 glDisable( GL_REGISTER_COMBINERS_NV );
699 glActiveTexture( GL_TEXTURE0 );
700 glDisable( GL_TEXTURE_2D );
701 glActiveTexture( GL_TEXTURE1 );
702 glDisable( GL_TEXTURE_1D );
703 glActiveTexture( GL_TEXTURE2 );
704 glDisable( GL_TEXTURE_2D );
705 glActiveTexture( GL_TEXTURE3 );
706 glDisable( GL_TEXTURE_2D );
708 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
709 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
710 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
711 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
713 GlobalOpenGL_debugAssertNoErrors();
714 g_vertexProgram_enabled = false;
720 const GLubyte* m_string;
721 const GLint m_length;
722 GLstringNV( const char* string ) : m_string( reinterpret_cast<const GLubyte*>( string ) ), m_length( GLint( string_length( string ) ) ){
726 GLstringNV g_light_origin( "light_origin" );
727 GLstringNV g_view_origin( "view_origin" );
728 GLstringNV g_light_color( "light_color" );
729 GLstringNV g_bumpGLSL_scale( "bump_scale" );
730 GLstringNV g_specular_exponent( "specular_exponent" );
732 void setVertexProgramEnvironment( const Vector3& localViewer ){
733 Matrix4 local2light( g_matrix4_identity );
734 matrix4_translate_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
735 matrix4_scale_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
736 matrix4_scale_by_vec3( local2light, Vector3( 1.0 / 512.0, 1.0 / 512.0, 1.0 / 512.0 ) );
737 matrix4_translate_by_vec3( local2light, vector3_negated( localViewer ) );
739 glActiveTexture( GL_TEXTURE3 );
740 glClientActiveTexture( GL_TEXTURE3 );
742 glMatrixMode( GL_TEXTURE );
743 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
744 glMatrixMode( GL_MODELVIEW );
746 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV );
747 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 4, GL_TEXTURE0_ARB, GL_IDENTITY_NV );
750 //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
753 glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
756 glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
759 //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
762 //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
764 GlobalOpenGL_debugAssertNoErrors();
770 bool g_vertexArray_enabled = false;
771 bool g_normalArray_enabled = false;
772 bool g_texcoordArray_enabled = false;
773 bool g_colorArray_enabled = false;
775 inline bool OpenGLState_less( const OpenGLState& self, const OpenGLState& other ){
776 //! Sort by sort-order override.
777 if ( self.m_sort != other.m_sort ) {
778 return self.m_sort < other.m_sort;
780 //! Sort by texture handle.
781 if ( self.m_texture != other.m_texture ) {
782 return self.m_texture < other.m_texture;
784 if ( self.m_texture1 != other.m_texture1 ) {
785 return self.m_texture1 < other.m_texture1;
787 if ( self.m_texture2 != other.m_texture2 ) {
788 return self.m_texture2 < other.m_texture2;
790 if ( self.m_texture3 != other.m_texture3 ) {
791 return self.m_texture3 < other.m_texture3;
793 if ( self.m_texture4 != other.m_texture4 ) {
794 return self.m_texture4 < other.m_texture4;
796 if ( self.m_texture5 != other.m_texture5 ) {
797 return self.m_texture5 < other.m_texture5;
799 if ( self.m_texture6 != other.m_texture6 ) {
800 return self.m_texture6 < other.m_texture6;
802 if ( self.m_texture7 != other.m_texture7 ) {
803 return self.m_texture7 < other.m_texture7;
805 //! Sort by state bit-vector.
806 if ( self.m_state != other.m_state ) {
807 return self.m_state < other.m_state;
809 //! Comparing address makes sure states are never equal.
810 return &self < &other;
813 void OpenGLState_constructDefault( OpenGLState& state ){
814 state.m_state = RENDER_DEFAULT;
817 state.m_texture1 = 0;
818 state.m_texture2 = 0;
819 state.m_texture3 = 0;
820 state.m_texture4 = 0;
821 state.m_texture5 = 0;
822 state.m_texture6 = 0;
823 state.m_texture7 = 0;
825 state.m_colour[0] = 1;
826 state.m_colour[1] = 1;
827 state.m_colour[2] = 1;
828 state.m_colour[3] = 1;
830 state.m_depthfunc = GL_LESS;
832 state.m_blend_src = GL_SRC_ALPHA;
833 state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
835 state.m_alphafunc = GL_ALWAYS;
836 state.m_alpharef = 0;
838 state.m_linewidth = 1;
839 state.m_pointsize = 1;
841 state.m_linestipple_factor = 1;
842 state.m_linestipple_pattern = 0xaaaa;
844 state.m_fog = OpenGLFogState();
848 /// \brief A container of Renderable references.
849 /// May contain the same Renderable multiple times, with different transforms.
850 class OpenGLStateBucket
853 struct RenderTransform
855 const Matrix4* m_transform;
856 const OpenGLRenderable *m_renderable;
857 const RendererLight* m_light;
859 RenderTransform( const OpenGLRenderable& renderable, const Matrix4& transform, const RendererLight* light )
860 : m_transform( &transform ), m_renderable( &renderable ), m_light( light ){
864 typedef std::vector<RenderTransform> Renderables;
869 Renderables m_renderables;
875 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const RendererLight* light = 0 ){
876 m_renderables.push_back( RenderTransform( renderable, modelview, light ) );
879 OpenGLState& state(){
883 void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
886 #define LIGHT_SHADER_DEBUG 0
888 #if LIGHT_SHADER_DEBUG
889 typedef std::vector<Shader*> LightDebugShaders;
890 LightDebugShaders g_lightDebugShaders;
893 class OpenGLStateLess
896 bool operator()( const OpenGLState& self, const OpenGLState& other ) const {
897 return OpenGLState_less( self, other );
901 typedef ConstReference<OpenGLState> OpenGLStateReference;
902 typedef std::map<OpenGLStateReference, OpenGLStateBucket*, OpenGLStateLess> OpenGLStates;
903 OpenGLStates g_state_sorted;
905 class OpenGLStateBucketAdd
907 OpenGLStateBucket& m_bucket;
908 const OpenGLRenderable& m_renderable;
909 const Matrix4& m_modelview;
911 using func = void(const RendererLight&);
913 OpenGLStateBucketAdd( OpenGLStateBucket& bucket, const OpenGLRenderable& renderable, const Matrix4& modelview ) :
914 m_bucket( bucket ), m_renderable( renderable ), m_modelview( modelview ){
917 void operator()( const RendererLight& light ){
918 m_bucket.addRenderable( m_renderable, m_modelview, &light );
926 using func = void(RendererLight&);
928 CountLights() : m_count( 0 ){
931 void operator()( const RendererLight& light ){
935 std::size_t count() const {
940 class OpenGLShader : public Shader
942 typedef std::list<OpenGLStateBucket*> Passes;
946 ModuleObservers m_observers;
948 OpenGLShader() : m_shader( 0 ), m_used( 0 ){
954 void construct( const char* name );
962 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
969 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const LightList* lights ){
970 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
972 #if LIGHT_SHADER_DEBUG
973 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
976 lights->forEachLight( makeCallback1( counter ) );
977 globalOutputStream() << "count = " << counter.count() << "\n";
978 for ( std::size_t i = 0; i < counter.count(); ++i )
980 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
986 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
988 OpenGLStateBucketAdd add( *( *i ), renderable, modelview );
989 lights->forEachLight(makeCallback( add ) );
995 ( *i )->addRenderable( renderable, modelview );
1000 void incrementUsed(){
1001 if ( ++m_used == 1 && m_shader != 0 ) {
1002 m_shader->SetInUse( true );
1006 void decrementUsed(){
1007 if ( --m_used == 0 && m_shader != 0 ) {
1008 m_shader->SetInUse( false );
1012 bool realised() const {
1013 return m_shader != 0;
1016 void attach( ModuleObserver& observer ){
1020 m_observers.attach( observer );
1023 void detach( ModuleObserver& observer ){
1025 observer.unrealise();
1027 m_observers.detach( observer );
1030 void realise( const CopiedString& name ){
1031 construct( name.c_str() );
1033 if ( m_used != 0 && m_shader != 0 ) {
1034 m_shader->SetInUse( true );
1037 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1039 g_state_sorted.insert( OpenGLStates::value_type( OpenGLStateReference( ( *i )->state() ), *i ) );
1042 m_observers.realise();
1046 m_observers.unrealise();
1048 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1050 g_state_sorted.erase( OpenGLStateReference( ( *i )->state() ) );
1056 qtexture_t& getTexture() const {
1057 ASSERT_NOTNULL( m_shader );
1058 return *m_shader->getTexture();
1061 unsigned int getFlags() const {
1062 ASSERT_NOTNULL( m_shader );
1063 return m_shader->getFlags();
1066 IShader& getShader() const {
1067 ASSERT_NOTNULL( m_shader );
1071 OpenGLState& appendDefaultPass(){
1072 m_passes.push_back( new OpenGLStateBucket );
1073 OpenGLState& state = m_passes.back()->state();
1074 OpenGLState_constructDefault( state );
1080 inline bool lightEnabled( const RendererLight& light, const LightCullable& cullable ){
1081 return cullable.testLight( light );
1084 typedef std::set<RendererLight*> RendererLights;
1086 #define DEBUG_LIGHT_SYNC 0
1088 class LinearLightList : public LightList
1090 LightCullable& m_cullable;
1091 RendererLights& m_allLights;
1092 Callback<void()> m_evaluateChanged;
1094 typedef std::list<RendererLight*> Lights;
1095 mutable Lights m_lights;
1096 mutable bool m_lightsChanged;
1098 LinearLightList( LightCullable& cullable, RendererLights& lights, const Callback<void()>& evaluateChanged ) :
1099 m_cullable( cullable ), m_allLights( lights ), m_evaluateChanged( evaluateChanged ){
1100 m_lightsChanged = true;
1103 void evaluateLights() const {
1104 m_evaluateChanged();
1105 if ( m_lightsChanged ) {
1106 m_lightsChanged = false;
1109 m_cullable.clearLights();
1110 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1112 if ( lightEnabled( *( *i ), m_cullable ) ) {
1113 m_lights.push_back( *i );
1114 m_cullable.insertLight( *( *i ) );
1118 #if ( DEBUG_LIGHT_SYNC )
1122 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1124 if ( lightEnabled( *( *i ), m_cullable ) ) {
1125 lights.push_back( *i );
1129 !std::lexicographical_compare( lights.begin(), lights.end(), m_lights.begin(), m_lights.end() )
1130 && !std::lexicographical_compare( m_lights.begin(), m_lights.end(), lights.begin(), lights.end() ),
1131 "lights out of sync"
1137 void forEachLight( const RendererLightCallback& callback ) const {
1140 for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i )
1142 callback( *( *i ) );
1146 void lightsChanged() const {
1147 m_lightsChanged = true;
1151 inline void setFogState( const OpenGLFogState& state ){
1152 glFogi( GL_FOG_MODE, state.mode );
1153 glFogf( GL_FOG_DENSITY, state.density );
1154 glFogf( GL_FOG_START, state.start );
1155 glFogf( GL_FOG_END, state.end );
1156 glFogi( GL_FOG_INDEX, state.index );
1157 glFogfv( GL_FOG_COLOR, vector4_to_array( state.colour ) );
1160 #define DEBUG_SHADERS 0
1162 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver
1164 class CreateOpenGLShader
1166 OpenGLShaderCache* m_cache;
1168 explicit CreateOpenGLShader( OpenGLShaderCache* cache = 0 )
1172 OpenGLShader* construct( const CopiedString& name ){
1173 OpenGLShader* shader = new OpenGLShader;
1174 if ( m_cache->realised() ) {
1175 shader->realise( name );
1180 void destroy( OpenGLShader* shader ){
1181 if ( m_cache->realised() ) {
1182 shader->unrealise();
1188 typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1190 std::size_t m_unrealised;
1192 bool m_lightingEnabled;
1193 bool m_lightingSupported;
1194 bool m_useShaderLanguage;
1198 : m_shaders( CreateOpenGLShader( this ) ),
1199 m_unrealised( 3 ), // wait until shaders, gl-context and textures are realised before creating any render-states
1200 m_lightingEnabled( true ),
1201 m_lightingSupported( false ),
1202 m_useShaderLanguage( false ),
1203 m_lightsChanged( true ),
1204 m_traverseRenderablesMutex( false ){
1207 ~OpenGLShaderCache(){
1208 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1210 globalOutputStream() << "leaked shader: " << makeQuoted( ( *i ).key.c_str() ) << "\n";
1214 Shader* capture( const char* name ){
1215 ASSERT_MESSAGE( name[0] == '$'
1219 || strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
1221 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1223 return m_shaders.capture( name ).get();
1226 void release( const char *name ){
1228 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1230 m_shaders.release( name );
1232 void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
1233 glMatrixMode( GL_PROJECTION );
1234 glLoadMatrixf( reinterpret_cast<const float*>( &projection ) );
1236 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1239 glMatrixMode( GL_MODELVIEW );
1240 glLoadMatrixf( reinterpret_cast<const float*>( &modelview ) );
1242 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1245 ASSERT_MESSAGE( realised(), "render states are not realised" );
1247 // global settings that are not set in renderstates
1248 glFrontFace( GL_CW );
1249 glCullFace( GL_BACK );
1250 glPolygonOffset( -1, 1 );
1252 const GLubyte pattern[132] = {
1253 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1254 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1255 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1256 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1257 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1258 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1259 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1260 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1261 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1262 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1263 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1264 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1265 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1266 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1267 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1268 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
1270 glPolygonStipple( pattern );
1272 glEnableClientState( GL_VERTEX_ARRAY );
1273 g_vertexArray_enabled = true;
1274 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1276 if ( GlobalOpenGL().GL_1_3() ) {
1277 glActiveTexture( GL_TEXTURE0 );
1278 glClientActiveTexture( GL_TEXTURE0 );
1281 if ( GlobalOpenGL().ARB_shader_objects() ) {
1282 glUseProgramObjectARB( 0 );
1283 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
1284 glDisableVertexAttribArrayARB( c_attr_Tangent );
1285 glDisableVertexAttribArrayARB( c_attr_Binormal );
1288 if ( globalstate & RENDER_TEXTURE ) {
1289 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1290 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
1293 OpenGLState current;
1294 OpenGLState_constructDefault( current );
1295 current.m_sort = OpenGLState::eSortFirst;
1297 // default renderstate settings
1298 glLineStipple( current.m_linestipple_factor, current.m_linestipple_pattern );
1299 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1300 glDisable( GL_LIGHTING );
1301 glDisable( GL_TEXTURE_2D );
1302 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1303 g_texcoordArray_enabled = false;
1304 glDisableClientState( GL_COLOR_ARRAY );
1305 g_colorArray_enabled = false;
1306 glDisableClientState( GL_NORMAL_ARRAY );
1307 g_normalArray_enabled = false;
1308 glDisable( GL_BLEND );
1309 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1310 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1311 glDisable( GL_CULL_FACE );
1312 glShadeModel( GL_FLAT );
1313 glDisable( GL_DEPTH_TEST );
1314 glDepthMask( GL_FALSE );
1315 glDisable( GL_ALPHA_TEST );
1316 glDisable( GL_LINE_STIPPLE );
1317 glDisable( GL_POLYGON_STIPPLE );
1318 glDisable( GL_POLYGON_OFFSET_LINE );
1320 glBindTexture( GL_TEXTURE_2D, 0 );
1321 glColor4f( 1,1,1,1 );
1322 glDepthFunc( GL_LESS );
1323 glAlphaFunc( GL_ALWAYS, 0 );
1327 glHint( GL_FOG_HINT, GL_NICEST );
1328 glDisable( GL_FOG );
1329 setFogState( OpenGLFogState() );
1331 GlobalOpenGL_debugAssertNoErrors();
1333 debug_string( "begin rendering" );
1334 for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
1336 ( *i ).second->render( current, globalstate, viewer );
1338 debug_string( "end rendering" );
1342 if ( --m_unrealised == 0 ) {
1343 if ( lightingSupported() && lightingEnabled() ) {
1344 if ( useShaderLanguage() ) {
1345 g_bumpGLSL.create();
1346 g_depthFillGLSL.create();
1351 g_depthFillARB.create();
1355 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1357 if ( !( *i ).value.empty() ) {
1358 ( *i ).value->realise( i->key );
1365 if ( ++m_unrealised == 1 ) {
1366 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1368 if ( !( *i ).value.empty() ) {
1369 ( *i ).value->unrealise();
1372 if ( GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled() ) {
1373 if ( useShaderLanguage() ) {
1374 g_bumpGLSL.destroy();
1375 g_depthFillGLSL.destroy();
1379 g_bumpARB.destroy();
1380 g_depthFillARB.destroy();
1387 return m_unrealised == 0;
1391 bool lightingEnabled() const {
1392 return m_lightingEnabled;
1395 bool lightingSupported() const {
1396 return m_lightingSupported;
1399 bool useShaderLanguage() const {
1400 return m_useShaderLanguage;
1403 void setLighting( bool supported, bool enabled ){
1404 bool refresh = ( m_lightingSupported && m_lightingEnabled ) != ( supported && enabled );
1408 GlobalShaderSystem().setLightingEnabled( supported && enabled );
1411 m_lightingSupported = supported;
1412 m_lightingEnabled = enabled;
1419 void extensionsInitialised(){
1420 setLighting( GlobalOpenGL().GL_1_3()
1421 && GlobalOpenGL().ARB_vertex_program()
1422 && GlobalOpenGL().ARB_fragment_program()
1423 && GlobalOpenGL().ARB_shader_objects()
1424 && GlobalOpenGL().ARB_vertex_shader()
1425 && GlobalOpenGL().ARB_fragment_shader()
1426 && GlobalOpenGL().ARB_shading_language_100(),
1430 if ( !lightingSupported() ) {
1431 globalOutputStream() << "Lighting mode requires OpenGL features not supported by your graphics drivers:\n";
1432 if ( !GlobalOpenGL().GL_1_3() ) {
1433 globalOutputStream() << " GL version 1.3 or better\n";
1435 if ( !GlobalOpenGL().ARB_vertex_program() ) {
1436 globalOutputStream() << " GL_ARB_vertex_program\n";
1438 if ( !GlobalOpenGL().ARB_fragment_program() ) {
1439 globalOutputStream() << " GL_ARB_fragment_program\n";
1441 if ( !GlobalOpenGL().ARB_shader_objects() ) {
1442 globalOutputStream() << " GL_ARB_shader_objects\n";
1444 if ( !GlobalOpenGL().ARB_vertex_shader() ) {
1445 globalOutputStream() << " GL_ARB_vertex_shader\n";
1447 if ( !GlobalOpenGL().ARB_fragment_shader() ) {
1448 globalOutputStream() << " GL_ARB_fragment_shader\n";
1450 if ( !GlobalOpenGL().ARB_shading_language_100() ) {
1451 globalOutputStream() << " GL_ARB_shading_language_100\n";
1456 void setLightingEnabled( bool enabled ){
1457 setLighting( m_lightingSupported, enabled );
1462 RendererLights m_lights;
1463 bool m_lightsChanged;
1464 typedef std::map<LightCullable*, LinearLightList> LightLists;
1465 LightLists m_lightLists;
1467 const LightList& attach( LightCullable& cullable ){
1468 return ( *m_lightLists.insert( LightLists::value_type( &cullable, LinearLightList( cullable, m_lights, EvaluateChangedCaller( *this ) ) ) ).first ).second;
1471 void detach( LightCullable& cullable ){
1472 m_lightLists.erase( &cullable );
1475 void changed( LightCullable& cullable ){
1476 LightLists::iterator i = m_lightLists.find( &cullable );
1477 ASSERT_MESSAGE( i != m_lightLists.end(), "cullable not attached" );
1478 ( *i ).second.lightsChanged();
1481 void attach( RendererLight& light ){
1482 ASSERT_MESSAGE( m_lights.find( &light ) == m_lights.end(), "light could not be attached" );
1483 m_lights.insert( &light );
1487 void detach( RendererLight& light ){
1488 ASSERT_MESSAGE( m_lights.find( &light ) != m_lights.end(), "light could not be detached" );
1489 m_lights.erase( &light );
1493 void changed( RendererLight& light ){
1494 m_lightsChanged = true;
1497 void evaluateChanged(){
1498 if ( m_lightsChanged ) {
1499 m_lightsChanged = false;
1500 for ( LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i )
1502 ( *i ).second.lightsChanged();
1507 typedef MemberCaller<OpenGLShaderCache, void(), &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1509 typedef std::set<const Renderable*> Renderables;
1510 Renderables m_renderables;
1511 mutable bool m_traverseRenderablesMutex;
1514 void attachRenderable( const Renderable& renderable ){
1515 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "attaching renderable during traversal" );
1516 ASSERT_MESSAGE( m_renderables.find( &renderable ) == m_renderables.end(), "renderable could not be attached" );
1517 m_renderables.insert( &renderable );
1520 void detachRenderable( const Renderable& renderable ){
1521 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "detaching renderable during traversal" );
1522 ASSERT_MESSAGE( m_renderables.find( &renderable ) != m_renderables.end(), "renderable could not be detached" );
1523 m_renderables.erase( &renderable );
1526 void forEachRenderable( const RenderableCallback& callback ) const {
1527 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "for-each during traversal" );
1528 m_traverseRenderablesMutex = true;
1529 for ( Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i )
1531 callback( *( *i ) );
1533 m_traverseRenderablesMutex = false;
1537 static OpenGLShaderCache* g_ShaderCache;
1539 void ShaderCache_extensionsInitialised(){
1540 g_ShaderCache->extensionsInitialised();
1543 void ShaderCache_setBumpEnabled( bool enabled ){
1544 g_ShaderCache->setLightingEnabled( enabled );
1548 Vector3 g_DebugShaderColours[256];
1549 Shader* g_defaultPointLight = 0;
1551 void ShaderCache_Construct(){
1552 g_ShaderCache = new OpenGLShaderCache;
1553 GlobalTexturesCache().attach( *g_ShaderCache );
1554 GlobalShaderSystem().attach( *g_ShaderCache );
1556 if ( g_pGameDescription->mGameType == "doom3" ) {
1557 g_defaultPointLight = g_ShaderCache->capture( "lights/defaultPointLight" );
1558 //Shader* overbright =
1559 g_ShaderCache->capture( "$OVERBRIGHT" );
1561 #if LIGHT_SHADER_DEBUG
1562 for ( std::size_t i = 0; i < 256; ++i )
1564 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1567 g_DebugShaderColours[0] = Vector3( 1, 0, 0 );
1568 g_DebugShaderColours[1] = Vector3( 1, 0.5, 0 );
1569 g_DebugShaderColours[2] = Vector3( 1, 1, 0 );
1570 g_DebugShaderColours[3] = Vector3( 0.5, 1, 0 );
1571 g_DebugShaderColours[4] = Vector3( 0, 1, 0 );
1572 g_DebugShaderColours[5] = Vector3( 0, 1, 0.5 );
1573 g_DebugShaderColours[6] = Vector3( 0, 1, 1 );
1574 g_DebugShaderColours[7] = Vector3( 0, 0.5, 1 );
1575 g_DebugShaderColours[8] = Vector3( 0, 0, 1 );
1576 g_DebugShaderColours[9] = Vector3( 0.5, 0, 1 );
1577 g_DebugShaderColours[10] = Vector3( 1, 0, 1 );
1578 g_DebugShaderColours[11] = Vector3( 1, 0, 0.5 );
1580 g_lightDebugShaders.reserve( 256 );
1581 StringOutputStream buffer( 256 );
1582 for ( std::size_t i = 0; i < 256; ++i )
1584 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1585 g_lightDebugShaders.push_back( g_ShaderCache->capture( buffer.c_str() ) );
1592 void ShaderCache_Destroy(){
1593 if ( g_pGameDescription->mGameType == "doom3" ) {
1594 g_ShaderCache->release( "lights/defaultPointLight" );
1595 g_ShaderCache->release( "$OVERBRIGHT" );
1596 g_defaultPointLight = 0;
1598 #if LIGHT_SHADER_DEBUG
1599 g_lightDebugShaders.clear();
1600 StringOutputStream buffer( 256 );
1601 for ( std::size_t i = 0; i < 256; ++i )
1603 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1604 g_ShaderCache->release( buffer.c_str() );
1609 GlobalShaderSystem().detach( *g_ShaderCache );
1610 GlobalTexturesCache().detach( *g_ShaderCache );
1611 delete g_ShaderCache;
1614 ShaderCache* GetShaderCache(){
1615 return g_ShaderCache;
1618 inline void setTextureState( GLint& current, const GLint& texture, GLenum textureUnit ){
1619 if ( texture != current ) {
1620 glActiveTexture( textureUnit );
1621 glClientActiveTexture( textureUnit );
1622 glBindTexture( GL_TEXTURE_2D, texture );
1623 GlobalOpenGL_debugAssertNoErrors();
1628 inline void setTextureState( GLint& current, const GLint& texture ){
1629 if ( texture != current ) {
1630 glBindTexture( GL_TEXTURE_2D, texture );
1631 GlobalOpenGL_debugAssertNoErrors();
1636 inline void setState( unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag ){
1637 if ( delta & state & flag ) {
1639 GlobalOpenGL_debugAssertNoErrors();
1641 else if ( delta & ~state & flag ) {
1642 glDisable( glflag );
1643 GlobalOpenGL_debugAssertNoErrors();
1647 void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
1648 debug_int( "sort", int(self.m_sort) );
1649 debug_int( "texture", self.m_texture );
1650 debug_int( "state", self.m_state );
1651 debug_int( "address", int(std::size_t( &self ) ) );
1655 if ( self.m_state & RENDER_OVERRIDE ) {
1656 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1659 const unsigned int state = self.m_state & globalstate;
1660 const unsigned int delta = state ^ current.m_state;
1662 GlobalOpenGL_debugAssertNoErrors();
1664 GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0;
1666 if ( program != current.m_program ) {
1667 if ( current.m_program != 0 ) {
1668 current.m_program->disable();
1669 glColor4fv( vector4_to_array( current.m_colour ) );
1670 debug_colour( "cleaning program" );
1673 current.m_program = program;
1675 if ( current.m_program != 0 ) {
1676 current.m_program->enable();
1680 if ( delta & state & RENDER_FILL ) {
1681 //qglPolygonMode (GL_BACK, GL_LINE);
1682 //qglPolygonMode (GL_FRONT, GL_FILL);
1683 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1684 GlobalOpenGL_debugAssertNoErrors();
1686 else if ( delta & ~state & RENDER_FILL ) {
1687 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1688 GlobalOpenGL_debugAssertNoErrors();
1691 setState( state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE );
1693 if ( delta & state & RENDER_LIGHTING ) {
1694 glEnable( GL_LIGHTING );
1695 glEnable( GL_COLOR_MATERIAL );
1696 glEnable( GL_RESCALE_NORMAL );
1697 glEnableClientState( GL_NORMAL_ARRAY );
1698 GlobalOpenGL_debugAssertNoErrors();
1699 g_normalArray_enabled = true;
1701 else if ( delta & ~state & RENDER_LIGHTING ) {
1702 glDisable( GL_LIGHTING );
1703 glDisable( GL_COLOR_MATERIAL );
1704 glDisable( GL_RESCALE_NORMAL );
1705 glDisableClientState( GL_NORMAL_ARRAY );
1706 GlobalOpenGL_debugAssertNoErrors();
1707 g_normalArray_enabled = false;
1710 if ( delta & state & RENDER_TEXTURE ) {
1711 GlobalOpenGL_debugAssertNoErrors();
1713 if ( GlobalOpenGL().GL_1_3() ) {
1714 glActiveTexture( GL_TEXTURE0 );
1715 glClientActiveTexture( GL_TEXTURE0 );
1718 glEnable( GL_TEXTURE_2D );
1720 glColor4f( 1,1,1,self.m_colour[3] );
1721 debug_colour( "setting texture" );
1723 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1724 GlobalOpenGL_debugAssertNoErrors();
1725 g_texcoordArray_enabled = true;
1727 else if ( delta & ~state & RENDER_TEXTURE ) {
1728 if ( GlobalOpenGL().GL_1_3() ) {
1729 glActiveTexture( GL_TEXTURE0 );
1730 glClientActiveTexture( GL_TEXTURE0 );
1733 glDisable( GL_TEXTURE_2D );
1734 glBindTexture( GL_TEXTURE_2D, 0 );
1735 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1737 GlobalOpenGL_debugAssertNoErrors();
1738 g_texcoordArray_enabled = false;
1741 if ( delta & state & RENDER_BLEND ) {
1742 // FIXME: some .TGA are buggy, have a completely empty alpha channel
1743 // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1744 // so I decided using GL_DECAL instead
1745 // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1746 // this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1748 glEnable( GL_BLEND );
1749 if ( GlobalOpenGL().GL_1_3() ) {
1750 glActiveTexture( GL_TEXTURE0 );
1752 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
1753 GlobalOpenGL_debugAssertNoErrors();
1755 else if ( delta & ~state & RENDER_BLEND ) {
1756 glDisable( GL_BLEND );
1757 if ( GlobalOpenGL().GL_1_3() ) {
1758 glActiveTexture( GL_TEXTURE0 );
1760 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1761 GlobalOpenGL_debugAssertNoErrors();
1764 setState( state, delta, RENDER_CULLFACE, GL_CULL_FACE );
1766 if ( delta & state & RENDER_SMOOTH ) {
1767 glShadeModel( GL_SMOOTH );
1768 GlobalOpenGL_debugAssertNoErrors();
1770 else if ( delta & ~state & RENDER_SMOOTH ) {
1771 glShadeModel( GL_FLAT );
1772 GlobalOpenGL_debugAssertNoErrors();
1775 setState( state, delta, RENDER_SCALED, GL_NORMALIZE ); // not GL_RESCALE_NORMAL
1777 setState( state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST );
1779 if ( delta & state & RENDER_DEPTHWRITE ) {
1780 glDepthMask( GL_TRUE );
1783 GLboolean depthEnabled;
1784 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1785 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1787 debug_string( "enabled depth-buffer writing" );
1789 GlobalOpenGL_debugAssertNoErrors();
1791 else if ( delta & ~state & RENDER_DEPTHWRITE ) {
1792 glDepthMask( GL_FALSE );
1795 GLboolean depthEnabled;
1796 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1797 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1799 debug_string( "disabled depth-buffer writing" );
1801 GlobalOpenGL_debugAssertNoErrors();
1804 if ( delta & state & RENDER_COLOURWRITE ) {
1805 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
1806 GlobalOpenGL_debugAssertNoErrors();
1808 else if ( delta & ~state & RENDER_COLOURWRITE ) {
1809 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
1810 GlobalOpenGL_debugAssertNoErrors();
1813 setState( state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST );
1815 if ( delta & state & RENDER_COLOURARRAY ) {
1816 glEnableClientState( GL_COLOR_ARRAY );
1817 GlobalOpenGL_debugAssertNoErrors();
1818 debug_colour( "enabling color_array" );
1819 g_colorArray_enabled = true;
1821 else if ( delta & ~state & RENDER_COLOURARRAY ) {
1822 glDisableClientState( GL_COLOR_ARRAY );
1823 glColor4fv( vector4_to_array( self.m_colour ) );
1824 debug_colour( "cleaning color_array" );
1825 GlobalOpenGL_debugAssertNoErrors();
1826 g_colorArray_enabled = false;
1829 if ( delta & ~state & RENDER_COLOURCHANGE ) {
1830 glColor4fv( vector4_to_array( self.m_colour ) );
1831 GlobalOpenGL_debugAssertNoErrors();
1834 setState( state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE );
1835 setState( state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH );
1837 setState( state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE );
1838 setState( state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH );
1840 setState( state, delta, RENDER_FOG, GL_FOG );
1842 if ( ( state & RENDER_FOG ) != 0 ) {
1843 setFogState( self.m_fog );
1844 GlobalOpenGL_debugAssertNoErrors();
1845 current.m_fog = self.m_fog;
1848 if ( state & RENDER_DEPTHTEST && self.m_depthfunc != current.m_depthfunc ) {
1849 glDepthFunc( self.m_depthfunc );
1850 GlobalOpenGL_debugAssertNoErrors();
1851 current.m_depthfunc = self.m_depthfunc;
1854 if ( state & RENDER_LINESTIPPLE
1855 && ( self.m_linestipple_factor != current.m_linestipple_factor
1856 || self.m_linestipple_pattern != current.m_linestipple_pattern ) ) {
1857 glLineStipple( self.m_linestipple_factor, self.m_linestipple_pattern );
1858 GlobalOpenGL_debugAssertNoErrors();
1859 current.m_linestipple_factor = self.m_linestipple_factor;
1860 current.m_linestipple_pattern = self.m_linestipple_pattern;
1864 if ( state & RENDER_ALPHATEST
1865 && ( self.m_alphafunc != current.m_alphafunc
1866 || self.m_alpharef != current.m_alpharef ) ) {
1867 glAlphaFunc( self.m_alphafunc, self.m_alpharef );
1868 GlobalOpenGL_debugAssertNoErrors();
1869 current.m_alphafunc = self.m_alphafunc;
1870 current.m_alpharef = self.m_alpharef;
1882 //if(state & RENDER_TEXTURE) != 0)
1884 texture0 = self.m_texture;
1885 texture1 = self.m_texture1;
1886 texture2 = self.m_texture2;
1887 texture3 = self.m_texture3;
1888 texture4 = self.m_texture4;
1889 texture5 = self.m_texture5;
1890 texture6 = self.m_texture6;
1891 texture7 = self.m_texture7;
1894 if ( GlobalOpenGL().GL_1_3() ) {
1895 setTextureState( current.m_texture, texture0, GL_TEXTURE0 );
1896 setTextureState( current.m_texture1, texture1, GL_TEXTURE1 );
1897 setTextureState( current.m_texture2, texture2, GL_TEXTURE2 );
1898 setTextureState( current.m_texture3, texture3, GL_TEXTURE3 );
1899 setTextureState( current.m_texture4, texture4, GL_TEXTURE4 );
1900 setTextureState( current.m_texture5, texture5, GL_TEXTURE5 );
1901 setTextureState( current.m_texture6, texture6, GL_TEXTURE6 );
1902 setTextureState( current.m_texture7, texture7, GL_TEXTURE7 );
1906 setTextureState( current.m_texture, texture0 );
1911 if ( state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3] ) {
1912 debug_colour( "setting alpha" );
1913 glColor4f( 1,1,1,self.m_colour[3] );
1914 GlobalOpenGL_debugAssertNoErrors();
1917 if ( !( state & RENDER_TEXTURE )
1918 && ( self.m_colour[0] != current.m_colour[0]
1919 || self.m_colour[1] != current.m_colour[1]
1920 || self.m_colour[2] != current.m_colour[2]
1921 || self.m_colour[3] != current.m_colour[3] ) ) {
1922 glColor4fv( vector4_to_array( self.m_colour ) );
1923 debug_colour( "setting non-texture" );
1924 GlobalOpenGL_debugAssertNoErrors();
1926 current.m_colour = self.m_colour;
1928 if ( state & RENDER_BLEND
1929 && ( self.m_blend_src != current.m_blend_src || self.m_blend_dst != current.m_blend_dst ) ) {
1930 glBlendFunc( self.m_blend_src, self.m_blend_dst );
1931 GlobalOpenGL_debugAssertNoErrors();
1932 current.m_blend_src = self.m_blend_src;
1933 current.m_blend_dst = self.m_blend_dst;
1936 if ( !( state & RENDER_FILL )
1937 && self.m_linewidth != current.m_linewidth ) {
1938 glLineWidth( self.m_linewidth );
1939 GlobalOpenGL_debugAssertNoErrors();
1940 current.m_linewidth = self.m_linewidth;
1943 if ( !( state & RENDER_FILL )
1944 && self.m_pointsize != current.m_pointsize ) {
1945 glPointSize( self.m_pointsize );
1946 GlobalOpenGL_debugAssertNoErrors();
1947 current.m_pointsize = self.m_pointsize;
1950 current.m_state = state;
1952 GlobalOpenGL_debugAssertNoErrors();
1955 void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1956 const Matrix4* transform = 0;
1958 for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
1960 //qglLoadMatrixf(i->m_transform);
1961 if ( !transform || ( transform != ( *i ).m_transform && !matrix4_affine_equal( *transform, *( *i ).m_transform ) ) ) {
1963 transform = ( *i ).m_transform;
1966 glMultMatrixf( reinterpret_cast<const float*>( transform ) );
1967 glFrontFace( ( ( current.m_state & RENDER_CULLFACE ) != 0 && matrix4_handedness( *transform ) == MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW );
1972 if ( current.m_program != 0 && ( *i ).m_light != 0 ) {
1973 const IShader& lightShader = static_cast<OpenGLShader*>( ( *i ).m_light->getShader() )->getShader();
1974 if ( lightShader.firstLayer() != 0 ) {
1975 GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
1976 GLuint attenuation_z = lightShader.lightFalloffImage() != 0
1977 ? lightShader.lightFalloffImage()->texture_number
1978 : static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
1980 setTextureState( current.m_texture3, attenuation_xy, GL_TEXTURE3 );
1981 glActiveTexture( GL_TEXTURE3 );
1982 glBindTexture( GL_TEXTURE_2D, attenuation_xy );
1983 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1984 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
1986 setTextureState( current.m_texture4, attenuation_z, GL_TEXTURE4 );
1987 glActiveTexture( GL_TEXTURE4 );
1988 glBindTexture( GL_TEXTURE_2D, attenuation_z );
1989 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1990 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1993 AABB lightBounds( ( *i ).m_light->aabb() );
1995 Matrix4 world2light( g_matrix4_identity );
1997 if ( ( *i ).m_light->isProjected() ) {
1998 world2light = ( *i ).m_light->projection();
1999 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
2000 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
2002 if ( !( *i ).m_light->isProjected() ) {
2003 matrix4_translate_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
2004 matrix4_scale_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
2005 matrix4_scale_by_vec3( world2light, Vector3( 1.0f / lightBounds.extents.x(), 1.0f / lightBounds.extents.y(), 1.0f / lightBounds.extents.z() ) );
2006 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
2007 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
2010 current.m_program->setParameters( viewer, *( *i ).m_transform, lightBounds.origin + ( *i ).m_light->offset(), ( *i ).m_light->colour(), world2light );
2011 debug_string( "set lightBounds parameters" );
2015 ( *i ).m_renderable->render( current.m_state );
2018 renderables.clear();
2021 void OpenGLStateBucket::render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
2022 if ( ( globalstate & m_state.m_state & RENDER_SCREEN ) != 0 ) {
2023 OpenGLState_apply( m_state, current, globalstate );
2024 debug_colour( "screen fill" );
2026 glMatrixMode( GL_PROJECTION );
2028 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
2030 glMatrixMode( GL_MODELVIEW );
2032 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
2034 glBegin( GL_QUADS );
2035 glVertex3f( -1, -1, 0 );
2036 glVertex3f( 1, -1, 0 );
2037 glVertex3f( 1, 1, 0 );
2038 glVertex3f( -1, 1, 0 );
2041 glMatrixMode( GL_PROJECTION );
2044 glMatrixMode( GL_MODELVIEW );
2047 else if ( !m_renderables.empty() ) {
2048 OpenGLState_apply( m_state, current, globalstate );
2049 Renderables_flush( m_renderables, current, globalstate, viewer );
2054 class OpenGLStateMap : public OpenGLStateLibrary
2056 typedef std::map<CopiedString, OpenGLState> States;
2060 ASSERT_MESSAGE( m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty" );
2063 typedef States::iterator iterator;
2066 return m_states.begin();
2070 return m_states.end();
2073 void getDefaultState( OpenGLState& state ) const {
2074 OpenGLState_constructDefault( state );
2077 void insert( const char* name, const OpenGLState& state ){
2078 bool inserted = m_states.insert( States::value_type( name, state ) ).second;
2079 ASSERT_MESSAGE( inserted, "OpenGLStateMap::insert: " << name << " already exists" );
2082 void erase( const char* name ){
2083 std::size_t count = m_states.erase( name );
2084 ASSERT_MESSAGE( count == 1, "OpenGLStateMap::erase: " << name << " does not exist" );
2087 iterator find( const char* name ){
2088 return m_states.find( name );
2092 OpenGLStateMap* g_openglStates = 0;
2094 inline GLenum convertBlendFactor( BlendFactor factor ){
2101 case BLEND_SRC_COLOUR:
2102 return GL_SRC_COLOR;
2103 case BLEND_ONE_MINUS_SRC_COLOUR:
2104 return GL_ONE_MINUS_SRC_COLOR;
2105 case BLEND_SRC_ALPHA:
2106 return GL_SRC_ALPHA;
2107 case BLEND_ONE_MINUS_SRC_ALPHA:
2108 return GL_ONE_MINUS_SRC_ALPHA;
2109 case BLEND_DST_COLOUR:
2110 return GL_DST_COLOR;
2111 case BLEND_ONE_MINUS_DST_COLOUR:
2112 return GL_ONE_MINUS_DST_COLOR;
2113 case BLEND_DST_ALPHA:
2114 return GL_DST_ALPHA;
2115 case BLEND_ONE_MINUS_DST_ALPHA:
2116 return GL_ONE_MINUS_DST_ALPHA;
2117 case BLEND_SRC_ALPHA_SATURATE:
2118 return GL_SRC_ALPHA_SATURATE;
2123 /// \todo Define special-case shaders in a data file.
2124 void OpenGLShader::construct( const char* name ){
2125 OpenGLState& state = appendDefaultPass();
2129 sscanf( name, "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2130 state.m_colour[3] = 1.0f;
2131 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2132 state.m_sort = OpenGLState::eSortFullbright;
2136 sscanf( name, "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2137 state.m_colour[3] = 0.5f;
2138 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_BLEND;
2139 state.m_sort = OpenGLState::eSortTranslucent;
2143 sscanf( name, "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2144 state.m_colour[3] = 1;
2145 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2146 state.m_sort = OpenGLState::eSortFullbright;
2147 state.m_depthfunc = GL_LESS;
2148 state.m_linewidth = 1;
2149 state.m_pointsize = 1;
2154 OpenGLStateMap::iterator i = g_openglStates->find( name );
2155 if ( i != g_openglStates->end() ) {
2156 state = ( *i ).second;
2160 if ( string_equal( name + 1, "POINT" ) ) {
2161 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2162 state.m_sort = OpenGLState::eSortControlFirst;
2163 state.m_pointsize = 4;
2165 else if ( string_equal( name + 1, "SELPOINT" ) ) {
2166 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2167 state.m_sort = OpenGLState::eSortControlFirst + 1;
2168 state.m_pointsize = 4;
2170 else if ( string_equal( name + 1, "BIGPOINT" ) ) {
2171 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2172 state.m_sort = OpenGLState::eSortControlFirst;
2173 state.m_pointsize = 6;
2175 else if ( string_equal( name + 1, "PIVOT" ) ) {
2176 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
2177 state.m_sort = OpenGLState::eSortGUI1;
2178 state.m_linewidth = 2;
2179 state.m_depthfunc = GL_LEQUAL;
2181 OpenGLState& hiddenLine = appendDefaultPass();
2182 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
2183 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2184 hiddenLine.m_linewidth = 2;
2185 hiddenLine.m_depthfunc = GL_GREATER;
2187 else if ( string_equal( name + 1, "LATTICE" ) ) {
2188 state.m_colour[0] = 1;
2189 state.m_colour[1] = 0.5;
2190 state.m_colour[2] = 0;
2191 state.m_colour[3] = 1;
2192 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2193 state.m_sort = OpenGLState::eSortControlFirst;
2195 else if ( string_equal( name + 1, "WIREFRAME" ) ) {
2196 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2197 state.m_sort = OpenGLState::eSortFullbright;
2199 else if ( string_equal( name + 1, "CAM_HIGHLIGHT" ) ) {
2200 state.m_colour[0] = 1;
2201 state.m_colour[1] = 0;
2202 state.m_colour[2] = 0;
2203 state.m_colour[3] = 0.3f;
2204 state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2205 state.m_sort = OpenGLState::eSortHighlight;
2206 state.m_depthfunc = GL_LEQUAL;
2208 else if ( string_equal( name + 1, "CAM_OVERLAY" ) ) {
2210 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2211 state.m_sort = OpenGLState::eSortOverlayFirst;
2213 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2214 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2215 state.m_depthfunc = GL_LEQUAL;
2217 OpenGLState& hiddenLine = appendDefaultPass();
2218 hiddenLine.m_colour[0] = 0.75;
2219 hiddenLine.m_colour[1] = 0.75;
2220 hiddenLine.m_colour[2] = 0.75;
2221 hiddenLine.m_colour[3] = 1;
2222 hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE | RENDER_LINESTIPPLE;
2223 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2224 hiddenLine.m_depthfunc = GL_GREATER;
2225 hiddenLine.m_linestipple_factor = 2;
2228 else if ( string_equal( name + 1, "XY_OVERLAY" ) ) {
2229 state.m_colour[0] = g_xywindow_globals.color_selbrushes[0];
2230 state.m_colour[1] = g_xywindow_globals.color_selbrushes[1];
2231 state.m_colour[2] = g_xywindow_globals.color_selbrushes[2];
2232 state.m_colour[3] = 1;
2233 state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
2234 state.m_sort = OpenGLState::eSortOverlayFirst;
2235 state.m_linewidth = 2;
2236 state.m_linestipple_factor = 3;
2238 else if ( string_equal( name + 1, "DEBUG_CLIPPED" ) ) {
2239 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2240 state.m_sort = OpenGLState::eSortLast;
2242 else if ( string_equal( name + 1, "POINTFILE" ) ) {
2243 state.m_colour[0] = 1;
2244 state.m_colour[1] = 0;
2245 state.m_colour[2] = 0;
2246 state.m_colour[3] = 1;
2247 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2248 state.m_sort = OpenGLState::eSortFullbright;
2249 state.m_linewidth = 4;
2251 else if ( string_equal( name + 1, "LIGHT_SPHERE" ) ) {
2252 state.m_colour[0] = .15f * .95f;
2253 state.m_colour[1] = .15f * .95f;
2254 state.m_colour[2] = .15f * .95f;
2255 state.m_colour[3] = 1;
2256 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2257 state.m_blend_src = GL_ONE;
2258 state.m_blend_dst = GL_ONE;
2259 state.m_sort = OpenGLState::eSortTranslucent;
2261 else if ( string_equal( name + 1, "Q3MAP2_LIGHT_SPHERE" ) ) {
2262 state.m_colour[0] = .05f;
2263 state.m_colour[1] = .05f;
2264 state.m_colour[2] = .05f;
2265 state.m_colour[3] = 1;
2266 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
2267 state.m_blend_src = GL_ONE;
2268 state.m_blend_dst = GL_ONE;
2269 state.m_sort = OpenGLState::eSortTranslucent;
2271 else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
2273 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2274 state.m_sort = OpenGLState::eSortOverlayFirst;
2276 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2277 state.m_sort = OpenGLState::eSortGUI1;
2278 state.m_depthfunc = GL_LEQUAL;
2280 OpenGLState& hiddenLine = appendDefaultPass();
2281 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_LINESTIPPLE;
2282 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2283 hiddenLine.m_depthfunc = GL_GREATER;
2286 else if ( string_equal( name + 1, "FLATSHADE_OVERLAY" ) ) {
2287 state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2288 state.m_sort = OpenGLState::eSortGUI1;
2289 state.m_depthfunc = GL_LEQUAL;
2291 OpenGLState& hiddenLine = appendDefaultPass();
2292 hiddenLine.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_POLYGONSTIPPLE;
2293 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2294 hiddenLine.m_depthfunc = GL_GREATER;
2296 else if ( string_equal( name + 1, "CLIPPER_OVERLAY" ) ) {
2297 state.m_colour[0] = g_xywindow_globals.color_clipper[0];
2298 state.m_colour[1] = g_xywindow_globals.color_clipper[1];
2299 state.m_colour[2] = g_xywindow_globals.color_clipper[2];
2300 state.m_colour[3] = 1;
2301 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE;
2302 state.m_sort = OpenGLState::eSortOverlayFirst;
2304 else if ( string_equal( name + 1, "OVERBRIGHT" ) ) {
2305 const float lightScale = 2;
2306 state.m_colour[0] = lightScale * 0.5f;
2307 state.m_colour[1] = lightScale * 0.5f;
2308 state.m_colour[2] = lightScale * 0.5f;
2309 state.m_colour[3] = 0.5;
2310 state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN;
2311 state.m_sort = OpenGLState::eSortOverbrighten;
2312 state.m_blend_src = GL_DST_COLOR;
2313 state.m_blend_dst = GL_SRC_COLOR;
2317 // default to something recognisable.. =)
2318 ERROR_MESSAGE( "hardcoded renderstate not found" );
2319 state.m_colour[0] = 1;
2320 state.m_colour[1] = 0;
2321 state.m_colour[2] = 1;
2322 state.m_colour[3] = 1;
2323 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2324 state.m_sort = OpenGLState::eSortFirst;
2328 // construction from IShader
2329 m_shader = QERApp_Shader_ForName( name );
2331 if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && m_shader->getBump()->texture_number != 0 ) { // is a bump shader
2332 state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM;
2333 state.m_colour[0] = 0;
2334 state.m_colour[1] = 0;
2335 state.m_colour[2] = 0;
2336 state.m_colour[3] = 1;
2337 state.m_sort = OpenGLState::eSortOpaque;
2339 if ( g_ShaderCache->useShaderLanguage() ) {
2340 state.m_program = &g_depthFillGLSL;
2344 state.m_program = &g_depthFillARB;
2347 OpenGLState& bumpPass = appendDefaultPass();
2348 bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
2349 bumpPass.m_texture1 = m_shader->getBump()->texture_number;
2350 bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
2352 bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2354 if ( g_ShaderCache->useShaderLanguage() ) {
2355 bumpPass.m_state |= RENDER_LIGHTING;
2356 bumpPass.m_program = &g_bumpGLSL;
2360 bumpPass.m_program = &g_bumpARB;
2363 bumpPass.m_depthfunc = GL_LEQUAL;
2364 bumpPass.m_sort = OpenGLState::eSortMultiFirst;
2365 bumpPass.m_blend_src = GL_ONE;
2366 bumpPass.m_blend_dst = GL_ONE;
2370 state.m_texture = m_shader->getTexture()->texture_number;
2372 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH;
2373 if ( ( m_shader->getFlags() & QER_CULL ) != 0 ) {
2374 if ( m_shader->getCull() == IShader::eCullBack ) {
2375 state.m_state |= RENDER_CULLFACE;
2380 state.m_state |= RENDER_CULLFACE;
2382 if ( ( m_shader->getFlags() & QER_ALPHATEST ) != 0 ) {
2383 state.m_state |= RENDER_ALPHATEST;
2384 IShader::EAlphaFunc alphafunc;
2385 m_shader->getAlphaFunc( &alphafunc, &state.m_alpharef );
2386 switch ( alphafunc )
2388 case IShader::eAlways:
2389 state.m_alphafunc = GL_ALWAYS;
2391 case IShader::eEqual:
2392 state.m_alphafunc = GL_EQUAL;
2394 case IShader::eLess:
2395 state.m_alphafunc = GL_LESS;
2397 case IShader::eGreater:
2398 state.m_alphafunc = GL_GREATER;
2400 case IShader::eLEqual:
2401 state.m_alphafunc = GL_LEQUAL;
2403 case IShader::eGEqual:
2404 state.m_alphafunc = GL_GEQUAL;
2408 reinterpret_cast<Vector3&>( state.m_colour ) = m_shader->getTexture()->color;
2409 state.m_colour[3] = 1.0f;
2411 if ( ( m_shader->getFlags() & QER_TRANS ) != 0 ) {
2412 state.m_state |= RENDER_BLEND;
2413 state.m_colour[3] = m_shader->getTrans();
2414 state.m_sort = OpenGLState::eSortTranslucent;
2415 BlendFunc blendFunc = m_shader->getBlendFunc();
2416 state.m_blend_src = convertBlendFactor( blendFunc.m_src );
2417 state.m_blend_dst = convertBlendFactor( blendFunc.m_dst );
2418 if ( state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA ) {
2419 state.m_state |= RENDER_DEPTHWRITE;
2424 state.m_state |= RENDER_DEPTHWRITE;
2425 state.m_sort = OpenGLState::eSortFullbright;
2432 #include "modulesystem/singletonmodule.h"
2433 #include "modulesystem/moduleregistry.h"
2435 class OpenGLStateLibraryAPI
2437 OpenGLStateMap m_stateMap;
2439 typedef OpenGLStateLibrary Type;
2441 STRING_CONSTANT( Name, "*" );
2443 OpenGLStateLibraryAPI(){
2444 g_openglStates = &m_stateMap;
2447 ~OpenGLStateLibraryAPI(){
2451 OpenGLStateLibrary* getTable(){
2456 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2457 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2458 StaticRegisterModule staticRegisterOpenGLStateLibrary( StaticOpenGLStateLibraryModule::instance() );
2460 class ShaderCacheDependencies : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef
2463 ShaderCacheDependencies() :
2464 GlobalShadersModuleRef( GlobalRadiant().getRequiredGameDescriptionKeyValue( "shaders" ) ){
2468 class ShaderCacheAPI
2470 ShaderCache* m_shaderCache;
2472 typedef ShaderCache Type;
2474 STRING_CONSTANT( Name, "*" );
2477 ShaderCache_Construct();
2479 m_shaderCache = GetShaderCache();
2483 ShaderCache_Destroy();
2486 ShaderCache* getTable(){
2487 return m_shaderCache;
2491 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2492 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2493 StaticRegisterModule staticRegisterShaderCache( StaticShaderCacheModule::instance() );