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"
58 #define DEBUG_RENDER 0
60 inline void debug_string( const char* string ){
62 globalOutputStream() << string << "\n";
66 inline void debug_int( const char* comment, int i ){
68 globalOutputStream() << comment << " " << i << "\n";
72 inline void debug_colour( const char* comment ){
75 glGetFloatv( GL_CURRENT_COLOR, reinterpret_cast<float*>( &v ) );
76 globalOutputStream() << comment << " colour: "
81 if ( glIsEnabled( GL_COLOR_ARRAY ) ) {
82 globalOutputStream() << " ARRAY";
84 if ( glIsEnabled( GL_COLOR_MATERIAL ) ) {
85 globalOutputStream() << " MATERIAL";
87 globalOutputStream() << "\n";
93 StringOutputStream g_renderer_stats;
94 std::size_t g_count_prims;
95 std::size_t g_count_states;
96 std::size_t g_count_transforms;
99 inline void count_prim(){
103 inline void count_state(){
107 inline void count_transform(){
108 ++g_count_transforms;
111 void Renderer_ResetStats(){
114 g_count_transforms = 0;
118 const char* Renderer_GetStats(){
119 g_renderer_stats.clear();
120 g_renderer_stats << "prims: " << Unsigned( g_count_prims )
121 << " | states: " << Unsigned( g_count_states )
122 << " | transforms: " << Unsigned( g_count_transforms )
123 << " | msec: " << g_timer.elapsed_msec();
124 return g_renderer_stats.c_str();
128 void printShaderLog( GLhandleARB object ){
129 GLint log_length = 0;
130 glGetObjectParameterivARB( object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length );
133 std::string log( log_length, ' ' );
135 glGetInfoLogARB( object, log_length, &log_length, &log[0] );
137 globalErrorStream() << StringRange( log.data(), log.data() + log_length ) << "\n";
140 void createShader( GLhandleARB program, const char* filename, GLenum type ){
141 GLhandleARB shader = glCreateShaderObjectARB( type );
142 GlobalOpenGL_debugAssertNoErrors();
146 std::size_t size = file_size( filename );
147 FileInputStream file( filename );
148 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
149 Array<GLcharARB> buffer( size );
150 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
152 const GLcharARB* string = buffer.data();
153 GLint length = GLint( size );
154 glShaderSourceARB( shader, 1, &string, &length );
159 glCompileShaderARB( shader );
162 glGetObjectParameterivARB( shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled );
165 printShaderLog( shader );
168 ASSERT_MESSAGE( compiled, "shader compile failed: " << makeQuoted( filename ) );
172 glAttachObjectARB( program, shader );
174 glDeleteObjectARB( shader );
176 GlobalOpenGL_debugAssertNoErrors();
179 void GLSLProgram_link( GLhandleARB program ){
180 glLinkProgramARB( program );
182 GLint linked = false;
183 glGetObjectParameterivARB( program, GL_OBJECT_LINK_STATUS_ARB, &linked );
186 printShaderLog( program );
189 ASSERT_MESSAGE( linked, "program link failed" );
192 void GLSLProgram_validate( GLhandleARB program ){
193 glValidateProgramARB( program );
195 GLint validated = false;
196 glGetObjectParameterivARB( program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated );
199 printShaderLog( program );
202 ASSERT_MESSAGE( validated, "program validation failed" );
205 bool g_bumpGLSLPass_enabled = false;
206 bool g_depthfillPass_enabled = false;
208 class GLSLBumpProgram : public GLProgram
211 GLhandleARB m_program;
212 qtexture_t* m_light_attenuation_xy;
213 qtexture_t* m_light_attenuation_z;
215 GLint u_light_origin;
218 GLint u_specular_exponent;
220 GLSLBumpProgram() : m_program( 0 ), m_light_attenuation_xy( 0 ), m_light_attenuation_z( 0 ){
225 m_program = glCreateProgramObjectARB();
229 StringOutputStream filename( 256 );
230 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.glsl";
231 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
233 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glsl";
234 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
237 GLSLProgram_link( m_program );
238 GLSLProgram_validate( m_program );
240 glUseProgramObjectARB( m_program );
242 glBindAttribLocationARB( m_program, c_attr_TexCoord0, "attr_TexCoord0" );
243 glBindAttribLocationARB( m_program, c_attr_Tangent, "attr_Tangent" );
244 glBindAttribLocationARB( m_program, c_attr_Binormal, "attr_Binormal" );
246 glUniform1iARB( glGetUniformLocationARB( m_program, "u_diffusemap" ), 0 );
247 glUniform1iARB( glGetUniformLocationARB( m_program, "u_bumpmap" ), 1 );
248 glUniform1iARB( glGetUniformLocationARB( m_program, "u_specularmap" ), 2 );
249 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_xy" ), 3 );
250 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_z" ), 4 );
252 u_view_origin = glGetUniformLocationARB( m_program, "u_view_origin" );
253 u_light_origin = glGetUniformLocationARB( m_program, "u_light_origin" );
254 u_light_color = glGetUniformLocationARB( m_program, "u_light_color" );
255 u_bump_scale = glGetUniformLocationARB( m_program, "u_bump_scale" );
256 u_specular_exponent = glGetUniformLocationARB( m_program, "u_specular_exponent" );
258 glUseProgramObjectARB( 0 );
260 GlobalOpenGL_debugAssertNoErrors();
264 glDeleteObjectARB( m_program );
269 glUseProgramObjectARB( m_program );
271 glEnableVertexAttribArrayARB( c_attr_TexCoord0 );
272 glEnableVertexAttribArrayARB( c_attr_Tangent );
273 glEnableVertexAttribArrayARB( c_attr_Binormal );
275 GlobalOpenGL_debugAssertNoErrors();
277 debug_string( "enable bump" );
278 g_bumpGLSLPass_enabled = true;
282 glUseProgramObjectARB( 0 );
284 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
285 glDisableVertexAttribArrayARB( c_attr_Tangent );
286 glDisableVertexAttribArrayARB( c_attr_Binormal );
288 GlobalOpenGL_debugAssertNoErrors();
290 debug_string( "disable bump" );
291 g_bumpGLSLPass_enabled = false;
294 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
295 Matrix4 world2local( localToWorld );
296 matrix4_affine_invert( world2local );
298 Vector3 localLight( origin );
299 matrix4_transform_point( world2local, localLight );
301 Vector3 localViewer( viewer );
302 matrix4_transform_point( world2local, localViewer );
304 Matrix4 local2light( world2light );
305 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
307 glUniform3fARB( u_view_origin, localViewer.x(), localViewer.y(), localViewer.z() );
308 glUniform3fARB( u_light_origin, localLight.x(), localLight.y(), localLight.z() );
309 glUniform3fARB( u_light_color, colour.x(), colour.y(), colour.z() );
310 glUniform1fARB( u_bump_scale, 1.0 );
311 glUniform1fARB( u_specular_exponent, 32.0 );
313 glActiveTexture( GL_TEXTURE3 );
314 glClientActiveTexture( GL_TEXTURE3 );
316 glMatrixMode( GL_TEXTURE );
317 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
318 glMatrixMode( GL_MODELVIEW );
320 GlobalOpenGL_debugAssertNoErrors();
324 GLSLBumpProgram g_bumpGLSL;
327 class GLSLDepthFillProgram : public GLProgram
330 GLhandleARB m_program;
334 m_program = glCreateProgramObjectARB();
338 StringOutputStream filename( 256 );
339 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glsl";
340 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
342 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glsl";
343 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
346 GLSLProgram_link( m_program );
347 GLSLProgram_validate( m_program );
349 GlobalOpenGL_debugAssertNoErrors();
353 glDeleteObjectARB( m_program );
357 glUseProgramObjectARB( m_program );
358 GlobalOpenGL_debugAssertNoErrors();
359 debug_string( "enable depthfill" );
360 g_depthfillPass_enabled = true;
363 glUseProgramObjectARB( 0 );
364 GlobalOpenGL_debugAssertNoErrors();
365 debug_string( "disable depthfill" );
366 g_depthfillPass_enabled = false;
368 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
372 GLSLDepthFillProgram g_depthFillGLSL;
377 void createProgram( const char* filename, GLenum type ){
378 std::size_t size = file_size( filename );
379 FileInputStream file( filename );
380 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
381 Array<GLcharARB> buffer( size );
382 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
384 glProgramStringARB( type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei( size ), buffer.data() );
386 if ( GL_INVALID_OPERATION == glGetError() ) {
388 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
389 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_ARB );
391 globalErrorStream() << reinterpret_cast<const char*>( filename ) << ":" << errPos << "\n" << reinterpret_cast<const char*>( errString );
393 ERROR_MESSAGE( "error in gl program" );
397 class ARBBumpProgram : public GLProgram
400 GLuint m_vertex_program;
401 GLuint m_fragment_program;
404 glEnable( GL_VERTEX_PROGRAM_ARB );
405 glEnable( GL_FRAGMENT_PROGRAM_ARB );
408 glGenProgramsARB( 1, &m_vertex_program );
409 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
410 StringOutputStream filename( 256 );
411 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.glp";
412 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
414 glGenProgramsARB( 1, &m_fragment_program );
415 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
417 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glp";
418 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
421 glDisable( GL_VERTEX_PROGRAM_ARB );
422 glDisable( GL_FRAGMENT_PROGRAM_ARB );
424 GlobalOpenGL_debugAssertNoErrors();
428 glDeleteProgramsARB( 1, &m_vertex_program );
429 glDeleteProgramsARB( 1, &m_fragment_program );
430 GlobalOpenGL_debugAssertNoErrors();
434 glEnable( GL_VERTEX_PROGRAM_ARB );
435 glEnable( GL_FRAGMENT_PROGRAM_ARB );
436 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
437 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
439 glEnableVertexAttribArrayARB( 8 );
440 glEnableVertexAttribArrayARB( 9 );
441 glEnableVertexAttribArrayARB( 10 );
442 glEnableVertexAttribArrayARB( 11 );
444 GlobalOpenGL_debugAssertNoErrors();
448 glDisable( GL_VERTEX_PROGRAM_ARB );
449 glDisable( GL_FRAGMENT_PROGRAM_ARB );
451 glDisableVertexAttribArrayARB( 8 );
452 glDisableVertexAttribArrayARB( 9 );
453 glDisableVertexAttribArrayARB( 10 );
454 glDisableVertexAttribArrayARB( 11 );
456 GlobalOpenGL_debugAssertNoErrors();
459 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
460 Matrix4 world2local( localToWorld );
461 matrix4_affine_invert( world2local );
463 Vector3 localLight( origin );
464 matrix4_transform_point( world2local, localLight );
466 Vector3 localViewer( viewer );
467 matrix4_transform_point( world2local, localViewer );
469 Matrix4 local2light( world2light );
470 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
473 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0 );
476 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1 );
479 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0 );
482 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0 );
485 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0 );
488 glActiveTexture( GL_TEXTURE3 );
489 glClientActiveTexture( GL_TEXTURE3 );
491 glMatrixMode( GL_TEXTURE );
492 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
493 glMatrixMode( GL_MODELVIEW );
495 GlobalOpenGL_debugAssertNoErrors();
499 class ARBDepthFillProgram : public GLProgram
502 GLuint m_vertex_program;
503 GLuint m_fragment_program;
506 glEnable( GL_VERTEX_PROGRAM_ARB );
507 glEnable( GL_FRAGMENT_PROGRAM_ARB );
510 glGenProgramsARB( 1, &m_vertex_program );
511 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
512 StringOutputStream filename( 256 );
513 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glp";
514 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
516 glGenProgramsARB( 1, &m_fragment_program );
517 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
519 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glp";
520 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
523 glDisable( GL_VERTEX_PROGRAM_ARB );
524 glDisable( GL_FRAGMENT_PROGRAM_ARB );
526 GlobalOpenGL_debugAssertNoErrors();
530 glDeleteProgramsARB( 1, &m_vertex_program );
531 glDeleteProgramsARB( 1, &m_fragment_program );
532 GlobalOpenGL_debugAssertNoErrors();
536 glEnable( GL_VERTEX_PROGRAM_ARB );
537 glEnable( GL_FRAGMENT_PROGRAM_ARB );
538 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
539 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
541 GlobalOpenGL_debugAssertNoErrors();
545 glDisable( GL_VERTEX_PROGRAM_ARB );
546 glDisable( GL_FRAGMENT_PROGRAM_ARB );
548 GlobalOpenGL_debugAssertNoErrors();
551 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
555 ARBBumpProgram g_bumpARB;
556 ARBDepthFillProgram g_depthFillARB;
560 // NV20 path (unfinished)
562 void createProgram( GLint program, const char* filename, GLenum type ){
563 std::size_t size = file_size( filename );
564 FileInputStream file( filename );
565 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
566 Array<GLubyte> buffer( size );
567 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
569 glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
571 if ( GL_INVALID_OPERATION == glGetError() ) {
573 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
574 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
576 globalErrorStream() << filename << ":" << errPos << "\n" << errString;
578 ERROR_MESSAGE( "error in gl program" );
582 GLuint m_vertex_program;
583 GLuint m_fragment_program;
584 qtexture_t* g_cube = 0;
585 qtexture_t* g_specular_lookup = 0;
586 qtexture_t* g_attenuation_xy = 0;
587 qtexture_t* g_attenuation_z = 0;
589 void createVertexProgram(){
591 glGenProgramsNV( 1, &m_vertex_program );
592 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
593 StringOutputStream filename( 256 );
594 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.nv30";
595 createProgram( m_vertex_program, filename.c_str(), GL_VERTEX_PROGRAM_NV );
597 glGenProgramsNV( 1, &m_fragment_program );
598 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
600 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.nv30";
601 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
604 g_cube = GlobalTexturesCache().capture( "generated/cube" );
605 g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
607 g_attenuation_xy = GlobalTexturesCache().capture( "lights/squarelight1" );
608 glActiveTexture( GL_TEXTURE0 );
609 glBindTexture( GL_TEXTURE_2D, g_attenuation_xy->texture_number );
610 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
611 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
613 g_attenuation_z = GlobalTexturesCache().capture( "lights/squarelight1a" );
614 glActiveTexture( GL_TEXTURE0 );
615 glBindTexture( GL_TEXTURE_2D, g_attenuation_z->texture_number );
616 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
617 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
619 GlobalOpenGL_debugAssertNoErrors();
622 void destroyVertexProgram(){
623 glDeleteProgramsNV( 1, &m_vertex_program );
624 glDeleteProgramsNV( 1, &m_fragment_program );
625 GlobalOpenGL_debugAssertNoErrors();
627 GlobalTexturesCache().release( g_cube );
628 GlobalTexturesCache().release( g_specular_lookup );
629 GlobalTexturesCache().release( g_attenuation_xy );
630 GlobalTexturesCache().release( g_attenuation_z );
633 bool g_vertexProgram_enabled = false;
635 void enableVertexProgram(){
636 //set up the register combiners
637 //two general combiners
638 glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
640 //combiner 0 does tex0+tex1 -> spare0
641 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB,
642 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
643 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
644 GL_UNSIGNED_INVERT_NV, GL_RGB );
645 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB,
646 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
647 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
648 GL_UNSIGNED_INVERT_NV, GL_RGB );
649 glCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV,
650 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
652 //combiner 1 does tex2 dot tex3 -> spare1
653 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE2_ARB,
654 GL_EXPAND_NORMAL_NV, GL_RGB );
655 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE3_ARB,
656 GL_EXPAND_NORMAL_NV, GL_RGB );
657 glCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
658 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
662 //final combiner outputs (1-spare0)*constant color 0*spare1
663 //do constant color 0*spare1 in the EF multiplier
664 glFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
665 glFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
667 //now do (1-spare0)*EF
668 glFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
669 glFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
670 glFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
671 glFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
673 glEnable( GL_VERTEX_PROGRAM_NV );
674 glEnable( GL_REGISTER_COMBINERS_NV );
675 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
676 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
678 glActiveTexture( GL_TEXTURE0 );
679 glEnable( GL_TEXTURE_2D );
680 glActiveTexture( GL_TEXTURE1 );
681 glEnable( GL_TEXTURE_1D );
682 glActiveTexture( GL_TEXTURE2 );
683 glEnable( GL_TEXTURE_2D );
684 glActiveTexture( GL_TEXTURE3 );
685 glEnable( GL_TEXTURE_2D );
687 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
688 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
689 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
690 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
692 GlobalOpenGL_debugAssertNoErrors();
693 g_vertexProgram_enabled = true;
696 void disableVertexProgram(){
697 glDisable( GL_VERTEX_PROGRAM_NV );
698 glDisable( GL_REGISTER_COMBINERS_NV );
700 glActiveTexture( GL_TEXTURE0 );
701 glDisable( GL_TEXTURE_2D );
702 glActiveTexture( GL_TEXTURE1 );
703 glDisable( GL_TEXTURE_1D );
704 glActiveTexture( GL_TEXTURE2 );
705 glDisable( GL_TEXTURE_2D );
706 glActiveTexture( GL_TEXTURE3 );
707 glDisable( GL_TEXTURE_2D );
709 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
710 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
711 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
712 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
714 GlobalOpenGL_debugAssertNoErrors();
715 g_vertexProgram_enabled = false;
721 const GLubyte* m_string;
722 const GLint m_length;
723 GLstringNV( const char* string ) : m_string( reinterpret_cast<const GLubyte*>( string ) ), m_length( GLint( string_length( string ) ) ){
727 GLstringNV g_light_origin( "light_origin" );
728 GLstringNV g_view_origin( "view_origin" );
729 GLstringNV g_light_color( "light_color" );
730 GLstringNV g_bumpGLSL_scale( "bump_scale" );
731 GLstringNV g_specular_exponent( "specular_exponent" );
733 void setVertexProgramEnvironment( const Vector3& localViewer ){
734 Matrix4 local2light( g_matrix4_identity );
735 matrix4_translate_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
736 matrix4_scale_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
737 matrix4_scale_by_vec3( local2light, Vector3( 1.0 / 512.0, 1.0 / 512.0, 1.0 / 512.0 ) );
738 matrix4_translate_by_vec3( local2light, vector3_negated( localViewer ) );
740 glActiveTexture( GL_TEXTURE3 );
741 glClientActiveTexture( GL_TEXTURE3 );
743 glMatrixMode( GL_TEXTURE );
744 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
745 glMatrixMode( GL_MODELVIEW );
747 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV );
748 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 4, GL_TEXTURE0_ARB, GL_IDENTITY_NV );
751 //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
754 glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
757 glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
760 //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
763 //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
765 GlobalOpenGL_debugAssertNoErrors();
771 bool g_vertexArray_enabled = false;
772 bool g_normalArray_enabled = false;
773 bool g_texcoordArray_enabled = false;
774 bool g_colorArray_enabled = false;
776 inline bool OpenGLState_less( const OpenGLState& self, const OpenGLState& other ){
777 //! Sort by sort-order override.
778 if ( self.m_sort != other.m_sort ) {
779 return self.m_sort < other.m_sort;
781 //! Sort by texture handle.
782 if ( self.m_texture != other.m_texture ) {
783 return self.m_texture < other.m_texture;
785 if ( self.m_texture1 != other.m_texture1 ) {
786 return self.m_texture1 < other.m_texture1;
788 if ( self.m_texture2 != other.m_texture2 ) {
789 return self.m_texture2 < other.m_texture2;
791 if ( self.m_texture3 != other.m_texture3 ) {
792 return self.m_texture3 < other.m_texture3;
794 if ( self.m_texture4 != other.m_texture4 ) {
795 return self.m_texture4 < other.m_texture4;
797 if ( self.m_texture5 != other.m_texture5 ) {
798 return self.m_texture5 < other.m_texture5;
800 if ( self.m_texture6 != other.m_texture6 ) {
801 return self.m_texture6 < other.m_texture6;
803 if ( self.m_texture7 != other.m_texture7 ) {
804 return self.m_texture7 < other.m_texture7;
806 //! Sort by state bit-vector.
807 if ( self.m_state != other.m_state ) {
808 return self.m_state < other.m_state;
810 //! Comparing address makes sure states are never equal.
811 return &self < &other;
814 void OpenGLState_constructDefault( OpenGLState& state ){
815 state.m_state = RENDER_DEFAULT;
818 state.m_texture1 = 0;
819 state.m_texture2 = 0;
820 state.m_texture3 = 0;
821 state.m_texture4 = 0;
822 state.m_texture5 = 0;
823 state.m_texture6 = 0;
824 state.m_texture7 = 0;
826 state.m_colour[0] = 1;
827 state.m_colour[1] = 1;
828 state.m_colour[2] = 1;
829 state.m_colour[3] = 1;
831 state.m_depthfunc = GL_LESS;
833 state.m_blend_src = GL_SRC_ALPHA;
834 state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
836 state.m_alphafunc = GL_ALWAYS;
837 state.m_alpharef = 0;
839 state.m_linewidth = 1;
840 state.m_pointsize = 1;
842 state.m_linestipple_factor = 1;
843 state.m_linestipple_pattern = 0xaaaa;
845 state.m_fog = OpenGLFogState();
851 /// \brief A container of Renderable references.
852 /// May contain the same Renderable multiple times, with different transforms.
853 class OpenGLStateBucket
856 struct RenderTransform
858 const Matrix4* m_transform;
859 const OpenGLRenderable *m_renderable;
860 const RendererLight* m_light;
862 RenderTransform( const OpenGLRenderable& renderable, const Matrix4& transform, const RendererLight* light )
863 : m_transform( &transform ), m_renderable( &renderable ), m_light( light ){
867 typedef std::vector<RenderTransform> Renderables;
872 Renderables m_renderables;
877 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const RendererLight* light = 0 ){
878 m_renderables.push_back( RenderTransform( renderable, modelview, light ) );
881 OpenGLState& state(){
885 void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
888 #define LIGHT_SHADER_DEBUG 0
890 #if LIGHT_SHADER_DEBUG
891 typedef std::vector<Shader*> LightDebugShaders;
892 LightDebugShaders g_lightDebugShaders;
895 class OpenGLStateLess
898 bool operator()( const OpenGLState& self, const OpenGLState& other ) const {
899 return OpenGLState_less( self, other );
903 typedef ConstReference<OpenGLState> OpenGLStateReference;
904 typedef std::map<OpenGLStateReference, OpenGLStateBucket*, OpenGLStateLess> OpenGLStates;
905 OpenGLStates g_state_sorted;
907 class OpenGLStateBucketAdd
909 OpenGLStateBucket& m_bucket;
910 const OpenGLRenderable& m_renderable;
911 const Matrix4& m_modelview;
913 typedef const RendererLight& first_argument_type;
915 OpenGLStateBucketAdd( OpenGLStateBucket& bucket, const OpenGLRenderable& renderable, const Matrix4& modelview ) :
916 m_bucket( bucket ), m_renderable( renderable ), m_modelview( modelview ){
918 void operator()( const RendererLight& light ){
919 m_bucket.addRenderable( m_renderable, m_modelview, &light );
927 typedef RendererLight& first_argument_type;
929 CountLights() : m_count( 0 ){
931 void operator()( const RendererLight& light ){
934 std::size_t count() const {
939 class OpenGLShader : public Shader
941 typedef std::list<OpenGLStateBucket*> Passes;
945 ModuleObservers m_observers;
947 OpenGLShader() : m_shader( 0 ), m_used( 0 ){
951 void construct( const char* name );
958 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
964 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const LightList* lights ){
965 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
967 #if LIGHT_SHADER_DEBUG
968 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
971 lights->forEachLight( makeCallback1( counter ) );
972 globalOutputStream() << "count = " << counter.count() << "\n";
973 for ( std::size_t i = 0; i < counter.count(); ++i )
975 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
981 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
983 OpenGLStateBucketAdd add( *( *i ), renderable, modelview );
984 lights->forEachLight( makeCallback1( add ) );
990 ( *i )->addRenderable( renderable, modelview );
994 void incrementUsed(){
995 if ( ++m_used == 1 && m_shader != 0 ) {
996 m_shader->SetInUse( true );
999 void decrementUsed(){
1000 if ( --m_used == 0 && m_shader != 0 ) {
1001 m_shader->SetInUse( false );
1004 bool realised() const {
1005 return m_shader != 0;
1007 void attach( ModuleObserver& observer ){
1011 m_observers.attach( observer );
1013 void detach( ModuleObserver& observer ){
1015 observer.unrealise();
1017 m_observers.detach( observer );
1019 void realise( const std::string& name ){
1020 construct( name.c_str() );
1022 if ( m_used != 0 && m_shader != 0 ) {
1023 m_shader->SetInUse( true );
1026 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1028 g_state_sorted.insert( OpenGLStates::value_type( OpenGLStateReference( ( *i )->state() ), *i ) );
1031 m_observers.realise();
1034 m_observers.unrealise();
1036 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1038 g_state_sorted.erase( OpenGLStateReference( ( *i )->state() ) );
1043 qtexture_t& getTexture() const {
1044 ASSERT_NOTNULL( m_shader );
1045 return *m_shader->getTexture();
1047 unsigned int getFlags() const {
1048 ASSERT_NOTNULL( m_shader );
1049 return m_shader->getFlags();
1051 IShader& getShader() const {
1052 ASSERT_NOTNULL( m_shader );
1055 OpenGLState& appendDefaultPass(){
1056 m_passes.push_back( new OpenGLStateBucket );
1057 OpenGLState& state = m_passes.back()->state();
1058 OpenGLState_constructDefault( state );
1064 inline bool lightEnabled( const RendererLight& light, const LightCullable& cullable ){
1065 return cullable.testLight( light );
1068 typedef std::set<RendererLight*> RendererLights;
1070 #define DEBUG_LIGHT_SYNC 0
1072 class LinearLightList : public LightList
1074 LightCullable& m_cullable;
1075 RendererLights& m_allLights;
1076 Callback m_evaluateChanged;
1078 typedef std::list<RendererLight*> Lights;
1079 mutable Lights m_lights;
1080 mutable bool m_lightsChanged;
1082 LinearLightList( LightCullable& cullable, RendererLights& lights, const Callback& evaluateChanged ) :
1083 m_cullable( cullable ), m_allLights( lights ), m_evaluateChanged( evaluateChanged ){
1084 m_lightsChanged = true;
1086 void evaluateLights() const {
1087 m_evaluateChanged();
1088 if ( m_lightsChanged ) {
1089 m_lightsChanged = false;
1092 m_cullable.clearLights();
1093 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1095 if ( lightEnabled( *( *i ), m_cullable ) ) {
1096 m_lights.push_back( *i );
1097 m_cullable.insertLight( *( *i ) );
1101 #if ( DEBUG_LIGHT_SYNC )
1105 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1107 if ( lightEnabled( *( *i ), m_cullable ) ) {
1108 lights.push_back( *i );
1112 !std::lexicographical_compare( lights.begin(), lights.end(), m_lights.begin(), m_lights.end() )
1113 && !std::lexicographical_compare( m_lights.begin(), m_lights.end(), lights.begin(), lights.end() ),
1114 "lights out of sync"
1119 void forEachLight( const RendererLightCallback& callback ) const {
1122 for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i )
1124 callback( *( *i ) );
1127 void lightsChanged() const {
1128 m_lightsChanged = true;
1132 inline void setFogState( const OpenGLFogState& state ){
1133 glFogi( GL_FOG_MODE, state.mode );
1134 glFogf( GL_FOG_DENSITY, state.density );
1135 glFogf( GL_FOG_START, state.start );
1136 glFogf( GL_FOG_END, state.end );
1137 glFogi( GL_FOG_INDEX, state.index );
1138 glFogfv( GL_FOG_COLOR, vector4_to_array( state.colour ) );
1141 #define DEBUG_SHADERS 0
1143 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver
1145 class CreateOpenGLShader
1147 OpenGLShaderCache* m_cache;
1149 explicit CreateOpenGLShader( OpenGLShaderCache* cache = 0 )
1152 OpenGLShader* construct( const std::string& name ){
1153 OpenGLShader* shader = new OpenGLShader;
1154 if ( m_cache->realised() ) {
1155 shader->realise( name );
1159 void destroy( OpenGLShader* shader ){
1160 if ( m_cache->realised() ) {
1161 shader->unrealise();
1167 typedef HashedCache<std::string, OpenGLShader, HashString, std::equal_to<std::string>, CreateOpenGLShader> Shaders;
1169 std::size_t m_unrealised;
1171 bool m_lightingEnabled;
1172 bool m_lightingSupported;
1173 bool m_useShaderLanguage;
1177 : m_shaders( CreateOpenGLShader( this ) ),
1178 m_unrealised( 3 ), // wait until shaders, gl-context and textures are realised before creating any render-states
1179 m_lightingEnabled( true ),
1180 m_lightingSupported( false ),
1181 m_useShaderLanguage( false ),
1182 m_lightsChanged( true ),
1183 m_traverseRenderablesMutex( false ){
1185 ~OpenGLShaderCache(){
1186 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1188 globalOutputStream() << "leaked shader: " << makeQuoted( ( *i ).first.c_str() ) << "\n";
1191 Shader* capture( const char* name ){
1192 ASSERT_MESSAGE( name[0] == '$'
1196 || strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
1198 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1200 return m_shaders.capture( name ).get();
1202 void release( const char *name ){
1204 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1206 m_shaders.release( name );
1208 void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
1209 glMatrixMode( GL_PROJECTION );
1210 glLoadMatrixf( reinterpret_cast<const float*>( &projection ) );
1212 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1215 glMatrixMode( GL_MODELVIEW );
1216 glLoadMatrixf( reinterpret_cast<const float*>( &modelview ) );
1218 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1221 ASSERT_MESSAGE( realised(), "render states are not realised" );
1223 // global settings that are not set in renderstates
1224 glFrontFace( GL_CW );
1225 glCullFace( GL_BACK );
1226 glPolygonOffset( -1, 1 );
1228 const GLubyte pattern[132] = {
1229 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1230 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1231 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1232 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1233 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1234 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1235 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1236 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1237 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1238 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1239 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1240 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1241 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1242 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1243 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1244 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
1246 glPolygonStipple( pattern );
1248 glEnableClientState( GL_VERTEX_ARRAY );
1249 g_vertexArray_enabled = true;
1250 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1252 if ( GlobalOpenGL().GL_1_3() ) {
1253 glActiveTexture( GL_TEXTURE0 );
1254 glClientActiveTexture( GL_TEXTURE0 );
1257 if ( GlobalOpenGL().ARB_shader_objects() ) {
1258 glUseProgramObjectARB( 0 );
1259 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
1260 glDisableVertexAttribArrayARB( c_attr_Tangent );
1261 glDisableVertexAttribArrayARB( c_attr_Binormal );
1264 if ( globalstate & RENDER_TEXTURE ) {
1265 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1266 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
1269 OpenGLState current;
1270 OpenGLState_constructDefault( current );
1271 current.m_sort = OpenGLState::eSortFirst;
1273 // default renderstate settings
1274 glLineStipple( current.m_linestipple_factor, current.m_linestipple_pattern );
1275 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1276 glDisable( GL_LIGHTING );
1277 glDisable( GL_TEXTURE_2D );
1278 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1279 g_texcoordArray_enabled = false;
1280 glDisableClientState( GL_COLOR_ARRAY );
1281 g_colorArray_enabled = false;
1282 glDisableClientState( GL_NORMAL_ARRAY );
1283 g_normalArray_enabled = false;
1284 glDisable( GL_BLEND );
1285 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1286 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1287 glDisable( GL_CULL_FACE );
1288 glShadeModel( GL_FLAT );
1289 glDisable( GL_DEPTH_TEST );
1290 glDepthMask( GL_FALSE );
1291 glDisable( GL_ALPHA_TEST );
1292 glDisable( GL_LINE_STIPPLE );
1293 glDisable( GL_POLYGON_STIPPLE );
1294 glDisable( GL_POLYGON_OFFSET_LINE );
1296 glBindTexture( GL_TEXTURE_2D, 0 );
1297 glColor4f( 1,1,1,1 );
1298 glDepthFunc( GL_LESS );
1299 glAlphaFunc( GL_ALWAYS, 0 );
1303 glHint( GL_FOG_HINT, GL_NICEST );
1304 glDisable( GL_FOG );
1305 setFogState( OpenGLFogState() );
1307 GlobalOpenGL_debugAssertNoErrors();
1309 debug_string( "begin rendering" );
1310 for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
1312 ( *i ).second->render( current, globalstate, viewer );
1314 debug_string( "end rendering" );
1317 if ( --m_unrealised == 0 ) {
1318 if ( lightingSupported() && lightingEnabled() ) {
1319 if ( useShaderLanguage() ) {
1320 g_bumpGLSL.create();
1321 g_depthFillGLSL.create();
1326 g_depthFillARB.create();
1330 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1332 if ( !( *i ).second.empty() ) {
1333 ( *i ).second->realise( i->first );
1339 if ( ++m_unrealised == 1 ) {
1340 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1342 if ( !( *i ).second.empty() ) {
1343 ( *i ).second->unrealise();
1346 if ( GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled() ) {
1347 if ( useShaderLanguage() ) {
1348 g_bumpGLSL.destroy();
1349 g_depthFillGLSL.destroy();
1353 g_bumpARB.destroy();
1354 g_depthFillARB.destroy();
1360 return m_unrealised == 0;
1364 bool lightingEnabled() const {
1365 return m_lightingEnabled;
1367 bool lightingSupported() const {
1368 return m_lightingSupported;
1370 bool useShaderLanguage() const {
1371 return m_useShaderLanguage;
1373 void setLighting( bool supported, bool enabled ){
1374 bool refresh = ( m_lightingSupported && m_lightingEnabled ) != ( supported && enabled );
1378 GlobalShaderSystem().setLightingEnabled( supported && enabled );
1381 m_lightingSupported = supported;
1382 m_lightingEnabled = enabled;
1388 void extensionsInitialised(){
1389 setLighting( GlobalOpenGL().GL_1_3()
1390 && GlobalOpenGL().ARB_vertex_program()
1391 && GlobalOpenGL().ARB_fragment_program()
1392 && GlobalOpenGL().ARB_shader_objects()
1393 && GlobalOpenGL().ARB_vertex_shader()
1394 && GlobalOpenGL().ARB_fragment_shader()
1395 && GlobalOpenGL().ARB_shading_language_100(),
1399 if ( !lightingSupported() ) {
1400 globalOutputStream() << "Lighting mode requires OpenGL features not supported by your graphics drivers:\n";
1401 if ( !GlobalOpenGL().GL_1_3() ) {
1402 globalOutputStream() << " GL version 1.3 or better\n";
1404 if ( !GlobalOpenGL().ARB_vertex_program() ) {
1405 globalOutputStream() << " GL_ARB_vertex_program\n";
1407 if ( !GlobalOpenGL().ARB_fragment_program() ) {
1408 globalOutputStream() << " GL_ARB_fragment_program\n";
1410 if ( !GlobalOpenGL().ARB_shader_objects() ) {
1411 globalOutputStream() << " GL_ARB_shader_objects\n";
1413 if ( !GlobalOpenGL().ARB_vertex_shader() ) {
1414 globalOutputStream() << " GL_ARB_vertex_shader\n";
1416 if ( !GlobalOpenGL().ARB_fragment_shader() ) {
1417 globalOutputStream() << " GL_ARB_fragment_shader\n";
1419 if ( !GlobalOpenGL().ARB_shading_language_100() ) {
1420 globalOutputStream() << " GL_ARB_shading_language_100\n";
1424 void setLightingEnabled( bool enabled ){
1425 setLighting( m_lightingSupported, enabled );
1430 RendererLights m_lights;
1431 bool m_lightsChanged;
1432 typedef std::map<LightCullable*, LinearLightList> LightLists;
1433 LightLists m_lightLists;
1435 const LightList& attach( LightCullable& cullable ){
1436 return ( *m_lightLists.insert( LightLists::value_type( &cullable, LinearLightList( cullable, m_lights, EvaluateChangedCaller( *this ) ) ) ).first ).second;
1438 void detach( LightCullable& cullable ){
1439 m_lightLists.erase( &cullable );
1441 void changed( LightCullable& cullable ){
1442 LightLists::iterator i = m_lightLists.find( &cullable );
1443 ASSERT_MESSAGE( i != m_lightLists.end(), "cullable not attached" );
1444 ( *i ).second.lightsChanged();
1446 void attach( RendererLight& light ){
1447 ASSERT_MESSAGE( m_lights.find( &light ) == m_lights.end(), "light could not be attached" );
1448 m_lights.insert( &light );
1451 void detach( RendererLight& light ){
1452 ASSERT_MESSAGE( m_lights.find( &light ) != m_lights.end(), "light could not be detached" );
1453 m_lights.erase( &light );
1456 void changed( RendererLight& light ){
1457 m_lightsChanged = true;
1459 void evaluateChanged(){
1460 if ( m_lightsChanged ) {
1461 m_lightsChanged = false;
1462 for ( LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i )
1464 ( *i ).second.lightsChanged();
1468 typedef MemberCaller<OpenGLShaderCache, &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1470 typedef std::set<const Renderable*> Renderables;
1471 Renderables m_renderables;
1472 mutable bool m_traverseRenderablesMutex;
1475 void attachRenderable( const Renderable& renderable ){
1476 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "attaching renderable during traversal" );
1477 ASSERT_MESSAGE( m_renderables.find( &renderable ) == m_renderables.end(), "renderable could not be attached" );
1478 m_renderables.insert( &renderable );
1480 void detachRenderable( const Renderable& renderable ){
1481 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "detaching renderable during traversal" );
1482 ASSERT_MESSAGE( m_renderables.find( &renderable ) != m_renderables.end(), "renderable could not be detached" );
1483 m_renderables.erase( &renderable );
1485 void forEachRenderable( const RenderableCallback& callback ) const {
1486 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "for-each during traversal" );
1487 m_traverseRenderablesMutex = true;
1488 for ( Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i )
1490 callback( *( *i ) );
1492 m_traverseRenderablesMutex = false;
1496 static OpenGLShaderCache* g_ShaderCache;
1498 void ShaderCache_extensionsInitialised(){
1499 g_ShaderCache->extensionsInitialised();
1502 void ShaderCache_setBumpEnabled( bool enabled ){
1503 g_ShaderCache->setLightingEnabled( enabled );
1507 Vector3 g_DebugShaderColours[256];
1508 Shader* g_defaultPointLight = 0;
1510 void ShaderCache_Construct(){
1511 g_ShaderCache = new OpenGLShaderCache;
1512 GlobalTexturesCache().attach( *g_ShaderCache );
1513 GlobalShaderSystem().attach( *g_ShaderCache );
1515 if ( g_pGameDescription->mGameType == "doom3" ) {
1516 g_defaultPointLight = g_ShaderCache->capture( "lights/defaultPointLight" );
1517 //Shader* overbright =
1518 g_ShaderCache->capture( "$OVERBRIGHT" );
1520 #if LIGHT_SHADER_DEBUG
1521 for ( std::size_t i = 0; i < 256; ++i )
1523 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1526 g_DebugShaderColours[0] = Vector3( 1, 0, 0 );
1527 g_DebugShaderColours[1] = Vector3( 1, 0.5, 0 );
1528 g_DebugShaderColours[2] = Vector3( 1, 1, 0 );
1529 g_DebugShaderColours[3] = Vector3( 0.5, 1, 0 );
1530 g_DebugShaderColours[4] = Vector3( 0, 1, 0 );
1531 g_DebugShaderColours[5] = Vector3( 0, 1, 0.5 );
1532 g_DebugShaderColours[6] = Vector3( 0, 1, 1 );
1533 g_DebugShaderColours[7] = Vector3( 0, 0.5, 1 );
1534 g_DebugShaderColours[8] = Vector3( 0, 0, 1 );
1535 g_DebugShaderColours[9] = Vector3( 0.5, 0, 1 );
1536 g_DebugShaderColours[10] = Vector3( 1, 0, 1 );
1537 g_DebugShaderColours[11] = Vector3( 1, 0, 0.5 );
1539 g_lightDebugShaders.reserve( 256 );
1540 StringOutputStream buffer( 256 );
1541 for ( std::size_t i = 0; i < 256; ++i )
1543 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1544 g_lightDebugShaders.push_back( g_ShaderCache->capture( buffer.c_str() ) );
1551 void ShaderCache_Destroy(){
1552 if ( g_pGameDescription->mGameType == "doom3" ) {
1553 g_ShaderCache->release( "lights/defaultPointLight" );
1554 g_ShaderCache->release( "$OVERBRIGHT" );
1555 g_defaultPointLight = 0;
1557 #if LIGHT_SHADER_DEBUG
1558 g_lightDebugShaders.clear();
1559 StringOutputStream buffer( 256 );
1560 for ( std::size_t i = 0; i < 256; ++i )
1562 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1563 g_ShaderCache->release( buffer.c_str() );
1568 GlobalShaderSystem().detach( *g_ShaderCache );
1569 GlobalTexturesCache().detach( *g_ShaderCache );
1570 delete g_ShaderCache;
1573 ShaderCache* GetShaderCache(){
1574 return g_ShaderCache;
1577 inline void setTextureState( GLint& current, const GLint& texture, GLenum textureUnit ){
1578 if ( texture != current ) {
1579 glActiveTexture( textureUnit );
1580 glClientActiveTexture( textureUnit );
1581 glBindTexture( GL_TEXTURE_2D, texture );
1582 GlobalOpenGL_debugAssertNoErrors();
1587 inline void setTextureState( GLint& current, const GLint& texture ){
1588 if ( texture != current ) {
1589 glBindTexture( GL_TEXTURE_2D, texture );
1590 GlobalOpenGL_debugAssertNoErrors();
1595 inline void setState( unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag ){
1596 if ( delta & state & flag ) {
1598 GlobalOpenGL_debugAssertNoErrors();
1600 else if ( delta & ~state & flag ) {
1601 glDisable( glflag );
1602 GlobalOpenGL_debugAssertNoErrors();
1606 void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
1607 debug_int( "sort", int(self.m_sort) );
1608 debug_int( "texture", self.m_texture );
1609 debug_int( "state", self.m_state );
1610 debug_int( "address", int(std::size_t( &self ) ) );
1614 if ( self.m_state & RENDER_OVERRIDE ) {
1615 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1618 const unsigned int state = self.m_state & globalstate;
1619 const unsigned int delta = state ^ current.m_state;
1621 GlobalOpenGL_debugAssertNoErrors();
1623 GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0;
1625 if ( program != current.m_program ) {
1626 if ( current.m_program != 0 ) {
1627 current.m_program->disable();
1628 glColor4fv( vector4_to_array( current.m_colour ) );
1629 debug_colour( "cleaning program" );
1632 current.m_program = program;
1634 if ( current.m_program != 0 ) {
1635 current.m_program->enable();
1639 if ( delta & state & RENDER_FILL ) {
1640 //qglPolygonMode (GL_BACK, GL_LINE);
1641 //qglPolygonMode (GL_FRONT, GL_FILL);
1642 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1643 GlobalOpenGL_debugAssertNoErrors();
1645 else if ( delta & ~state & RENDER_FILL ) {
1646 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1647 GlobalOpenGL_debugAssertNoErrors();
1650 setState( state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE );
1652 if ( delta & state & RENDER_LIGHTING ) {
1653 glEnable( GL_LIGHTING );
1654 glEnable( GL_COLOR_MATERIAL );
1655 glEnable( GL_RESCALE_NORMAL );
1656 glEnableClientState( GL_NORMAL_ARRAY );
1657 GlobalOpenGL_debugAssertNoErrors();
1658 g_normalArray_enabled = true;
1660 else if ( delta & ~state & RENDER_LIGHTING ) {
1661 glDisable( GL_LIGHTING );
1662 glDisable( GL_COLOR_MATERIAL );
1663 glDisable( GL_RESCALE_NORMAL );
1664 glDisableClientState( GL_NORMAL_ARRAY );
1665 GlobalOpenGL_debugAssertNoErrors();
1666 g_normalArray_enabled = false;
1669 if ( delta & state & RENDER_TEXTURE ) {
1670 GlobalOpenGL_debugAssertNoErrors();
1672 if ( GlobalOpenGL().GL_1_3() ) {
1673 glActiveTexture( GL_TEXTURE0 );
1674 glClientActiveTexture( GL_TEXTURE0 );
1677 glEnable( GL_TEXTURE_2D );
1679 glColor4f( 1,1,1,self.m_colour[3] );
1680 debug_colour( "setting texture" );
1682 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1683 GlobalOpenGL_debugAssertNoErrors();
1684 g_texcoordArray_enabled = true;
1686 else if ( delta & ~state & RENDER_TEXTURE ) {
1687 if ( GlobalOpenGL().GL_1_3() ) {
1688 glActiveTexture( GL_TEXTURE0 );
1689 glClientActiveTexture( GL_TEXTURE0 );
1692 glDisable( GL_TEXTURE_2D );
1693 glBindTexture( GL_TEXTURE_2D, 0 );
1694 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1696 GlobalOpenGL_debugAssertNoErrors();
1697 g_texcoordArray_enabled = false;
1700 if ( delta & state & RENDER_BLEND ) {
1701 // FIXME: some .TGA are buggy, have a completely empty alpha channel
1702 // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1703 // so I decided using GL_DECAL instead
1704 // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1705 // this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1707 glEnable( GL_BLEND );
1708 if ( GlobalOpenGL().GL_1_3() ) {
1709 glActiveTexture( GL_TEXTURE0 );
1711 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
1712 GlobalOpenGL_debugAssertNoErrors();
1714 else if ( delta & ~state & RENDER_BLEND ) {
1715 glDisable( GL_BLEND );
1716 if ( GlobalOpenGL().GL_1_3() ) {
1717 glActiveTexture( GL_TEXTURE0 );
1719 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1720 GlobalOpenGL_debugAssertNoErrors();
1723 setState( state, delta, RENDER_CULLFACE, GL_CULL_FACE );
1725 if ( delta & state & RENDER_SMOOTH ) {
1726 glShadeModel( GL_SMOOTH );
1727 GlobalOpenGL_debugAssertNoErrors();
1729 else if ( delta & ~state & RENDER_SMOOTH ) {
1730 glShadeModel( GL_FLAT );
1731 GlobalOpenGL_debugAssertNoErrors();
1734 setState( state, delta, RENDER_SCALED, GL_NORMALIZE ); // not GL_RESCALE_NORMAL
1736 setState( state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST );
1738 if ( delta & state & RENDER_DEPTHWRITE ) {
1739 glDepthMask( GL_TRUE );
1742 GLboolean depthEnabled;
1743 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1744 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1746 debug_string( "enabled depth-buffer writing" );
1748 GlobalOpenGL_debugAssertNoErrors();
1750 else if ( delta & ~state & RENDER_DEPTHWRITE ) {
1751 glDepthMask( GL_FALSE );
1754 GLboolean depthEnabled;
1755 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1756 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1758 debug_string( "disabled depth-buffer writing" );
1760 GlobalOpenGL_debugAssertNoErrors();
1763 if ( delta & state & RENDER_COLOURWRITE ) {
1764 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
1765 GlobalOpenGL_debugAssertNoErrors();
1767 else if ( delta & ~state & RENDER_COLOURWRITE ) {
1768 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
1769 GlobalOpenGL_debugAssertNoErrors();
1772 setState( state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST );
1774 if ( delta & state & RENDER_COLOURARRAY ) {
1775 glEnableClientState( GL_COLOR_ARRAY );
1776 GlobalOpenGL_debugAssertNoErrors();
1777 debug_colour( "enabling color_array" );
1778 g_colorArray_enabled = true;
1780 else if ( delta & ~state & RENDER_COLOURARRAY ) {
1781 glDisableClientState( GL_COLOR_ARRAY );
1782 glColor4fv( vector4_to_array( self.m_colour ) );
1783 debug_colour( "cleaning color_array" );
1784 GlobalOpenGL_debugAssertNoErrors();
1785 g_colorArray_enabled = false;
1788 if ( delta & ~state & RENDER_COLOURCHANGE ) {
1789 glColor4fv( vector4_to_array( self.m_colour ) );
1790 GlobalOpenGL_debugAssertNoErrors();
1793 setState( state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE );
1794 setState( state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH );
1796 setState( state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE );
1797 setState( state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH );
1799 setState( state, delta, RENDER_FOG, GL_FOG );
1801 if ( ( state & RENDER_FOG ) != 0 ) {
1802 setFogState( self.m_fog );
1803 GlobalOpenGL_debugAssertNoErrors();
1804 current.m_fog = self.m_fog;
1807 if ( state & RENDER_DEPTHTEST && self.m_depthfunc != current.m_depthfunc ) {
1808 glDepthFunc( self.m_depthfunc );
1809 GlobalOpenGL_debugAssertNoErrors();
1810 current.m_depthfunc = self.m_depthfunc;
1813 if ( state & RENDER_LINESTIPPLE
1814 && ( self.m_linestipple_factor != current.m_linestipple_factor
1815 || self.m_linestipple_pattern != current.m_linestipple_pattern ) ) {
1816 glLineStipple( self.m_linestipple_factor, self.m_linestipple_pattern );
1817 GlobalOpenGL_debugAssertNoErrors();
1818 current.m_linestipple_factor = self.m_linestipple_factor;
1819 current.m_linestipple_pattern = self.m_linestipple_pattern;
1823 if ( state & RENDER_ALPHATEST
1824 && ( self.m_alphafunc != current.m_alphafunc
1825 || self.m_alpharef != current.m_alpharef ) ) {
1826 glAlphaFunc( self.m_alphafunc, self.m_alpharef );
1827 GlobalOpenGL_debugAssertNoErrors();
1828 current.m_alphafunc = self.m_alphafunc;
1829 current.m_alpharef = self.m_alpharef;
1841 //if(state & RENDER_TEXTURE) != 0)
1843 texture0 = self.m_texture;
1844 texture1 = self.m_texture1;
1845 texture2 = self.m_texture2;
1846 texture3 = self.m_texture3;
1847 texture4 = self.m_texture4;
1848 texture5 = self.m_texture5;
1849 texture6 = self.m_texture6;
1850 texture7 = self.m_texture7;
1853 if ( GlobalOpenGL().GL_1_3() ) {
1854 setTextureState( current.m_texture, texture0, GL_TEXTURE0 );
1855 setTextureState( current.m_texture1, texture1, GL_TEXTURE1 );
1856 setTextureState( current.m_texture2, texture2, GL_TEXTURE2 );
1857 setTextureState( current.m_texture3, texture3, GL_TEXTURE3 );
1858 setTextureState( current.m_texture4, texture4, GL_TEXTURE4 );
1859 setTextureState( current.m_texture5, texture5, GL_TEXTURE5 );
1860 setTextureState( current.m_texture6, texture6, GL_TEXTURE6 );
1861 setTextureState( current.m_texture7, texture7, GL_TEXTURE7 );
1865 setTextureState( current.m_texture, texture0 );
1870 if ( state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3] ) {
1871 debug_colour( "setting alpha" );
1872 glColor4f( 1,1,1,self.m_colour[3] );
1873 GlobalOpenGL_debugAssertNoErrors();
1876 if ( !( state & RENDER_TEXTURE )
1877 && ( self.m_colour[0] != current.m_colour[0]
1878 || self.m_colour[1] != current.m_colour[1]
1879 || self.m_colour[2] != current.m_colour[2]
1880 || self.m_colour[3] != current.m_colour[3] ) ) {
1881 glColor4fv( vector4_to_array( self.m_colour ) );
1882 debug_colour( "setting non-texture" );
1883 GlobalOpenGL_debugAssertNoErrors();
1885 current.m_colour = self.m_colour;
1887 if ( state & RENDER_BLEND
1888 && ( self.m_blend_src != current.m_blend_src || self.m_blend_dst != current.m_blend_dst ) ) {
1889 glBlendFunc( self.m_blend_src, self.m_blend_dst );
1890 GlobalOpenGL_debugAssertNoErrors();
1891 current.m_blend_src = self.m_blend_src;
1892 current.m_blend_dst = self.m_blend_dst;
1895 if ( !( state & RENDER_FILL )
1896 && self.m_linewidth != current.m_linewidth ) {
1897 glLineWidth( self.m_linewidth );
1898 GlobalOpenGL_debugAssertNoErrors();
1899 current.m_linewidth = self.m_linewidth;
1902 if ( !( state & RENDER_FILL )
1903 && self.m_pointsize != current.m_pointsize ) {
1904 glPointSize( self.m_pointsize );
1905 GlobalOpenGL_debugAssertNoErrors();
1906 current.m_pointsize = self.m_pointsize;
1909 current.m_state = state;
1911 GlobalOpenGL_debugAssertNoErrors();
1914 void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1915 const Matrix4* transform = 0;
1917 for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
1919 //qglLoadMatrixf(i->m_transform);
1920 if ( !transform || ( transform != ( *i ).m_transform && !matrix4_affine_equal( *transform, *( *i ).m_transform ) ) ) {
1922 transform = ( *i ).m_transform;
1925 glMultMatrixf( reinterpret_cast<const float*>( transform ) );
1926 glFrontFace( ( ( current.m_state & RENDER_CULLFACE ) != 0 && matrix4_handedness( *transform ) == MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW );
1931 if ( current.m_program != 0 && ( *i ).m_light != 0 ) {
1932 const IShader& lightShader = static_cast<OpenGLShader*>( ( *i ).m_light->getShader() )->getShader();
1933 if ( lightShader.firstLayer() != 0 ) {
1934 GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
1935 GLuint attenuation_z = lightShader.lightFalloffImage() != 0
1936 ? lightShader.lightFalloffImage()->texture_number
1937 : static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
1939 setTextureState( current.m_texture3, attenuation_xy, GL_TEXTURE3 );
1940 glActiveTexture( GL_TEXTURE3 );
1941 glBindTexture( GL_TEXTURE_2D, attenuation_xy );
1942 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1943 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
1945 setTextureState( current.m_texture4, attenuation_z, GL_TEXTURE4 );
1946 glActiveTexture( GL_TEXTURE4 );
1947 glBindTexture( GL_TEXTURE_2D, attenuation_z );
1948 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1949 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1952 AABB lightBounds( ( *i ).m_light->aabb() );
1954 Matrix4 world2light( g_matrix4_identity );
1956 if ( ( *i ).m_light->isProjected() ) {
1957 world2light = ( *i ).m_light->projection();
1958 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
1959 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
1961 if ( !( *i ).m_light->isProjected() ) {
1962 matrix4_translate_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
1963 matrix4_scale_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
1964 matrix4_scale_by_vec3( world2light, Vector3( 1.0f / lightBounds.extents.x(), 1.0f / lightBounds.extents.y(), 1.0f / lightBounds.extents.z() ) );
1965 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
1966 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
1969 current.m_program->setParameters( viewer, *( *i ).m_transform, lightBounds.origin + ( *i ).m_light->offset(), ( *i ).m_light->colour(), world2light );
1970 debug_string( "set lightBounds parameters" );
1974 ( *i ).m_renderable->render( current.m_state );
1977 renderables.clear();
1980 void OpenGLStateBucket::render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1981 if ( ( globalstate & m_state.m_state & RENDER_SCREEN ) != 0 ) {
1982 OpenGLState_apply( m_state, current, globalstate );
1983 debug_colour( "screen fill" );
1985 glMatrixMode( GL_PROJECTION );
1987 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1989 glMatrixMode( GL_MODELVIEW );
1991 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1993 glBegin( GL_QUADS );
1994 glVertex3f( -1, -1, 0 );
1995 glVertex3f( 1, -1, 0 );
1996 glVertex3f( 1, 1, 0 );
1997 glVertex3f( -1, 1, 0 );
2000 glMatrixMode( GL_PROJECTION );
2003 glMatrixMode( GL_MODELVIEW );
2006 else if ( !m_renderables.empty() ) {
2007 OpenGLState_apply( m_state, current, globalstate );
2008 Renderables_flush( m_renderables, current, globalstate, viewer );
2013 class OpenGLStateMap : public OpenGLStateLibrary
2015 typedef std::map<std::string, OpenGLState> States;
2019 ASSERT_MESSAGE( m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty" );
2022 typedef States::iterator iterator;
2024 return m_states.begin();
2027 return m_states.end();
2030 void getDefaultState( OpenGLState& state ) const {
2031 OpenGLState_constructDefault( state );
2034 void insert( const char* name, const OpenGLState& state ){
2035 bool inserted = m_states.insert( States::value_type( name, state ) ).second;
2036 ASSERT_MESSAGE( inserted, "OpenGLStateMap::insert: " << name << " already exists" );
2038 void erase( const char* name ){
2039 std::size_t count = m_states.erase( name );
2040 ASSERT_MESSAGE( count == 1, "OpenGLStateMap::erase: " << name << " does not exist" );
2043 iterator find( const char* name ){
2044 return m_states.find( name );
2048 OpenGLStateMap* g_openglStates = 0;
2050 inline GLenum convertBlendFactor( BlendFactor factor ){
2057 case BLEND_SRC_COLOUR:
2058 return GL_SRC_COLOR;
2059 case BLEND_ONE_MINUS_SRC_COLOUR:
2060 return GL_ONE_MINUS_SRC_COLOR;
2061 case BLEND_SRC_ALPHA:
2062 return GL_SRC_ALPHA;
2063 case BLEND_ONE_MINUS_SRC_ALPHA:
2064 return GL_ONE_MINUS_SRC_ALPHA;
2065 case BLEND_DST_COLOUR:
2066 return GL_DST_COLOR;
2067 case BLEND_ONE_MINUS_DST_COLOUR:
2068 return GL_ONE_MINUS_DST_COLOR;
2069 case BLEND_DST_ALPHA:
2070 return GL_DST_ALPHA;
2071 case BLEND_ONE_MINUS_DST_ALPHA:
2072 return GL_ONE_MINUS_DST_ALPHA;
2073 case BLEND_SRC_ALPHA_SATURATE:
2074 return GL_SRC_ALPHA_SATURATE;
2079 /// \todo Define special-case shaders in a data file.
2080 void OpenGLShader::construct( const char* name ){
2081 OpenGLState& state = appendDefaultPass();
2085 sscanf( name, "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2086 state.m_colour[3] = 1.0f;
2087 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2088 state.m_sort = OpenGLState::eSortFullbright;
2092 sscanf( name, "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2093 state.m_colour[3] = 0.5f;
2094 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_BLEND;
2095 state.m_sort = OpenGLState::eSortTranslucent;
2099 sscanf( name, "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2100 state.m_colour[3] = 1;
2101 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2102 state.m_sort = OpenGLState::eSortFullbright;
2103 state.m_depthfunc = GL_LESS;
2104 state.m_linewidth = 1;
2105 state.m_pointsize = 1;
2110 OpenGLStateMap::iterator i = g_openglStates->find( name );
2111 if ( i != g_openglStates->end() ) {
2112 state = ( *i ).second;
2116 if ( string_equal( name + 1, "POINT" ) ) {
2117 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2118 state.m_sort = OpenGLState::eSortControlFirst;
2119 state.m_pointsize = 4;
2121 else if ( string_equal( name + 1, "SELPOINT" ) ) {
2122 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2123 state.m_sort = OpenGLState::eSortControlFirst + 1;
2124 state.m_pointsize = 4;
2126 else if ( string_equal( name + 1, "BIGPOINT" ) ) {
2127 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2128 state.m_sort = OpenGLState::eSortControlFirst;
2129 state.m_pointsize = 6;
2131 else if ( string_equal( name + 1, "PIVOT" ) ) {
2132 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
2133 state.m_sort = OpenGLState::eSortGUI1;
2134 state.m_linewidth = 2;
2135 state.m_depthfunc = GL_LEQUAL;
2137 OpenGLState& hiddenLine = appendDefaultPass();
2138 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
2139 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2140 hiddenLine.m_linewidth = 2;
2141 hiddenLine.m_depthfunc = GL_GREATER;
2143 else if ( string_equal( name + 1, "LATTICE" ) ) {
2144 state.m_colour[0] = 1;
2145 state.m_colour[1] = 0.5;
2146 state.m_colour[2] = 0;
2147 state.m_colour[3] = 1;
2148 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2149 state.m_sort = OpenGLState::eSortControlFirst;
2151 else if ( string_equal( name + 1, "WIREFRAME" ) ) {
2152 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2153 state.m_sort = OpenGLState::eSortFullbright;
2155 else if ( string_equal( name + 1, "CAM_HIGHLIGHT" ) ) {
2156 state.m_colour[0] = 1;
2157 state.m_colour[1] = 0;
2158 state.m_colour[2] = 0;
2159 state.m_colour[3] = 0.3f;
2160 state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2161 state.m_sort = OpenGLState::eSortHighlight;
2162 state.m_depthfunc = GL_LEQUAL;
2164 else if ( string_equal( name + 1, "CAM_OVERLAY" ) ) {
2166 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2167 state.m_sort = OpenGLState::eSortOverlayFirst;
2169 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2170 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2171 state.m_depthfunc = GL_LEQUAL;
2173 OpenGLState& hiddenLine = appendDefaultPass();
2174 hiddenLine.m_colour[0] = 0.75;
2175 hiddenLine.m_colour[1] = 0.75;
2176 hiddenLine.m_colour[2] = 0.75;
2177 hiddenLine.m_colour[3] = 1;
2178 hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE | RENDER_LINESTIPPLE;
2179 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2180 hiddenLine.m_depthfunc = GL_GREATER;
2181 hiddenLine.m_linestipple_factor = 2;
2184 else if ( string_equal( name + 1, "XY_OVERLAY" ) ) {
2185 state.m_colour[0] = g_xywindow_globals.color_selbrushes[0];
2186 state.m_colour[1] = g_xywindow_globals.color_selbrushes[1];
2187 state.m_colour[2] = g_xywindow_globals.color_selbrushes[2];
2188 state.m_colour[3] = 1;
2189 state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
2190 state.m_sort = OpenGLState::eSortOverlayFirst;
2191 state.m_linewidth = 2;
2192 state.m_linestipple_factor = 3;
2194 else if ( string_equal( name + 1, "DEBUG_CLIPPED" ) ) {
2195 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2196 state.m_sort = OpenGLState::eSortLast;
2198 else if ( string_equal( name + 1, "POINTFILE" ) ) {
2199 state.m_colour[0] = 1;
2200 state.m_colour[1] = 0;
2201 state.m_colour[2] = 0;
2202 state.m_colour[3] = 1;
2203 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2204 state.m_sort = OpenGLState::eSortFullbright;
2205 state.m_linewidth = 4;
2207 else if ( string_equal( name + 1, "LIGHT_SPHERE" ) ) {
2208 state.m_colour[0] = .15f * .95f;
2209 state.m_colour[1] = .15f * .95f;
2210 state.m_colour[2] = .15f * .95f;
2211 state.m_colour[3] = 1;
2212 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2213 state.m_blend_src = GL_ONE;
2214 state.m_blend_dst = GL_ONE;
2215 state.m_sort = OpenGLState::eSortTranslucent;
2217 else if ( string_equal( name + 1, "Q3MAP2_LIGHT_SPHERE" ) ) {
2218 state.m_colour[0] = .05f;
2219 state.m_colour[1] = .05f;
2220 state.m_colour[2] = .05f;
2221 state.m_colour[3] = 1;
2222 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
2223 state.m_blend_src = GL_ONE;
2224 state.m_blend_dst = GL_ONE;
2225 state.m_sort = OpenGLState::eSortTranslucent;
2227 else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
2229 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2230 state.m_sort = OpenGLState::eSortOverlayFirst;
2232 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2233 state.m_sort = OpenGLState::eSortGUI1;
2234 state.m_depthfunc = GL_LEQUAL;
2236 OpenGLState& hiddenLine = appendDefaultPass();
2237 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_LINESTIPPLE;
2238 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2239 hiddenLine.m_depthfunc = GL_GREATER;
2242 else if ( string_equal( name + 1, "FLATSHADE_OVERLAY" ) ) {
2243 state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2244 state.m_sort = OpenGLState::eSortGUI1;
2245 state.m_depthfunc = GL_LEQUAL;
2247 OpenGLState& hiddenLine = appendDefaultPass();
2248 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;
2249 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2250 hiddenLine.m_depthfunc = GL_GREATER;
2252 else if ( string_equal( name + 1, "CLIPPER_OVERLAY" ) ) {
2253 state.m_colour[0] = g_xywindow_globals.color_clipper[0];
2254 state.m_colour[1] = g_xywindow_globals.color_clipper[1];
2255 state.m_colour[2] = g_xywindow_globals.color_clipper[2];
2256 state.m_colour[3] = 1;
2257 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE;
2258 state.m_sort = OpenGLState::eSortOverlayFirst;
2260 else if ( string_equal( name + 1, "OVERBRIGHT" ) ) {
2261 const float lightScale = 2;
2262 state.m_colour[0] = lightScale * 0.5f;
2263 state.m_colour[1] = lightScale * 0.5f;
2264 state.m_colour[2] = lightScale * 0.5f;
2265 state.m_colour[3] = 0.5;
2266 state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN;
2267 state.m_sort = OpenGLState::eSortOverbrighten;
2268 state.m_blend_src = GL_DST_COLOR;
2269 state.m_blend_dst = GL_SRC_COLOR;
2273 // default to something recognisable.. =)
2274 ERROR_MESSAGE( "hardcoded renderstate not found" );
2275 state.m_colour[0] = 1;
2276 state.m_colour[1] = 0;
2277 state.m_colour[2] = 1;
2278 state.m_colour[3] = 1;
2279 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2280 state.m_sort = OpenGLState::eSortFirst;
2284 // construction from IShader
2285 m_shader = QERApp_Shader_ForName( name );
2287 if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && m_shader->getBump()->texture_number != 0 ) { // is a bump shader
2288 state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM;
2289 state.m_colour[0] = 0;
2290 state.m_colour[1] = 0;
2291 state.m_colour[2] = 0;
2292 state.m_colour[3] = 1;
2293 state.m_sort = OpenGLState::eSortOpaque;
2295 if ( g_ShaderCache->useShaderLanguage() ) {
2296 state.m_program = &g_depthFillGLSL;
2300 state.m_program = &g_depthFillARB;
2303 OpenGLState& bumpPass = appendDefaultPass();
2304 bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
2305 bumpPass.m_texture1 = m_shader->getBump()->texture_number;
2306 bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
2308 bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2310 if ( g_ShaderCache->useShaderLanguage() ) {
2311 bumpPass.m_state |= RENDER_LIGHTING;
2312 bumpPass.m_program = &g_bumpGLSL;
2316 bumpPass.m_program = &g_bumpARB;
2319 bumpPass.m_depthfunc = GL_LEQUAL;
2320 bumpPass.m_sort = OpenGLState::eSortMultiFirst;
2321 bumpPass.m_blend_src = GL_ONE;
2322 bumpPass.m_blend_dst = GL_ONE;
2326 state.m_texture = m_shader->getTexture()->texture_number;
2328 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH;
2329 if ( ( m_shader->getFlags() & QER_CULL ) != 0 ) {
2330 if ( m_shader->getCull() == IShader::eCullBack ) {
2331 state.m_state |= RENDER_CULLFACE;
2336 state.m_state |= RENDER_CULLFACE;
2338 if ( ( m_shader->getFlags() & QER_ALPHATEST ) != 0 ) {
2339 state.m_state |= RENDER_ALPHATEST;
2340 IShader::EAlphaFunc alphafunc;
2341 m_shader->getAlphaFunc( &alphafunc, &state.m_alpharef );
2342 switch ( alphafunc )
2344 case IShader::eAlways:
2345 state.m_alphafunc = GL_ALWAYS;
2346 case IShader::eEqual:
2347 state.m_alphafunc = GL_EQUAL;
2348 case IShader::eLess:
2349 state.m_alphafunc = GL_LESS;
2350 case IShader::eGreater:
2351 state.m_alphafunc = GL_GREATER;
2352 case IShader::eLEqual:
2353 state.m_alphafunc = GL_LEQUAL;
2354 case IShader::eGEqual:
2355 state.m_alphafunc = GL_GEQUAL;
2358 reinterpret_cast<Vector3&>( state.m_colour ) = m_shader->getTexture()->color;
2359 state.m_colour[3] = 1.0f;
2361 if ( ( m_shader->getFlags() & QER_TRANS ) != 0 ) {
2362 state.m_state |= RENDER_BLEND;
2363 state.m_colour[3] = m_shader->getTrans();
2364 state.m_sort = OpenGLState::eSortTranslucent;
2365 BlendFunc blendFunc = m_shader->getBlendFunc();
2366 state.m_blend_src = convertBlendFactor( blendFunc.m_src );
2367 state.m_blend_dst = convertBlendFactor( blendFunc.m_dst );
2368 if ( state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA ) {
2369 state.m_state |= RENDER_DEPTHWRITE;
2374 state.m_state |= RENDER_DEPTHWRITE;
2375 state.m_sort = OpenGLState::eSortFullbright;
2382 #include "modulesystem/singletonmodule.h"
2383 #include "modulesystem/moduleregistry.h"
2385 class OpenGLStateLibraryAPI
2387 OpenGLStateMap m_stateMap;
2389 typedef OpenGLStateLibrary Type;
2390 STRING_CONSTANT( Name, "*" );
2392 OpenGLStateLibraryAPI(){
2393 g_openglStates = &m_stateMap;
2395 ~OpenGLStateLibraryAPI(){
2398 OpenGLStateLibrary* getTable(){
2403 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2404 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2405 StaticRegisterModule staticRegisterOpenGLStateLibrary( StaticOpenGLStateLibraryModule::instance() );
2407 class ShaderCacheDependencies : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef
2410 ShaderCacheDependencies() :
2411 GlobalShadersModuleRef( GlobalRadiant().getRequiredGameDescriptionKeyValue( "shaders" ) ){
2415 class ShaderCacheAPI
2417 ShaderCache* m_shaderCache;
2419 typedef ShaderCache Type;
2420 STRING_CONSTANT( Name, "*" );
2423 ShaderCache_Construct();
2425 m_shaderCache = GetShaderCache();
2428 ShaderCache_Destroy();
2430 ShaderCache* getTable(){
2431 return m_shaderCache;
2435 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2436 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2437 StaticRegisterModule staticRegisterShaderCache( StaticShaderCacheModule::instance() );