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"
55 #include "camwindow.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 );
132 Array<char> log( log_length );
133 glGetInfoLogARB( object, log_length, &log_length, log.data() );
135 globalErrorStream() << StringRange( log.begin(), log.begin() + log_length ) << "\n";
138 void createShader( GLhandleARB program, const char* filename, GLenum type ){
139 GLhandleARB shader = glCreateShaderObjectARB( type );
140 GlobalOpenGL_debugAssertNoErrors();
144 std::size_t size = file_size( filename );
145 FileInputStream file( filename );
146 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
147 Array<GLcharARB> buffer( size );
148 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
150 const GLcharARB* string = buffer.data();
151 GLint length = GLint( size );
152 glShaderSourceARB( shader, 1, &string, &length );
157 glCompileShaderARB( shader );
160 glGetObjectParameterivARB( shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled );
163 printShaderLog( shader );
166 ASSERT_MESSAGE( compiled, "shader compile failed: " << makeQuoted( filename ) );
170 glAttachObjectARB( program, shader );
172 glDeleteObjectARB( shader );
174 GlobalOpenGL_debugAssertNoErrors();
177 void GLSLProgram_link( GLhandleARB program ){
178 glLinkProgramARB( program );
180 GLint linked = false;
181 glGetObjectParameterivARB( program, GL_OBJECT_LINK_STATUS_ARB, &linked );
184 printShaderLog( program );
187 ASSERT_MESSAGE( linked, "program link failed" );
190 void GLSLProgram_validate( GLhandleARB program ){
191 glValidateProgramARB( program );
193 GLint validated = false;
194 glGetObjectParameterivARB( program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated );
197 printShaderLog( program );
200 ASSERT_MESSAGE( validated, "program validation failed" );
203 bool g_bumpGLSLPass_enabled = false;
204 bool g_depthfillPass_enabled = false;
206 class GLSLBumpProgram : public GLProgram
209 GLhandleARB m_program;
210 qtexture_t* m_light_attenuation_xy;
211 qtexture_t* m_light_attenuation_z;
213 GLint u_light_origin;
216 GLint u_specular_exponent;
218 GLSLBumpProgram() : m_program( 0 ), m_light_attenuation_xy( 0 ), m_light_attenuation_z( 0 ){
223 m_program = glCreateProgramObjectARB();
227 StringOutputStream filename( 256 );
228 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_vp.glsl";
229 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
231 filename << GlobalRadiant().getDataPath() << "gl/lighting_DBS_omni_fp.glsl";
232 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
235 GLSLProgram_link( m_program );
236 GLSLProgram_validate( m_program );
238 glUseProgramObjectARB( m_program );
240 glBindAttribLocationARB( m_program, c_attr_TexCoord0, "attr_TexCoord0" );
241 glBindAttribLocationARB( m_program, c_attr_Tangent, "attr_Tangent" );
242 glBindAttribLocationARB( m_program, c_attr_Binormal, "attr_Binormal" );
244 glUniform1iARB( glGetUniformLocationARB( m_program, "u_diffusemap" ), 0 );
245 glUniform1iARB( glGetUniformLocationARB( m_program, "u_bumpmap" ), 1 );
246 glUniform1iARB( glGetUniformLocationARB( m_program, "u_specularmap" ), 2 );
247 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_xy" ), 3 );
248 glUniform1iARB( glGetUniformLocationARB( m_program, "u_attenuationmap_z" ), 4 );
250 u_view_origin = glGetUniformLocationARB( m_program, "u_view_origin" );
251 u_light_origin = glGetUniformLocationARB( m_program, "u_light_origin" );
252 u_light_color = glGetUniformLocationARB( m_program, "u_light_color" );
253 u_bump_scale = glGetUniformLocationARB( m_program, "u_bump_scale" );
254 u_specular_exponent = glGetUniformLocationARB( m_program, "u_specular_exponent" );
256 glUseProgramObjectARB( 0 );
258 GlobalOpenGL_debugAssertNoErrors();
262 glDeleteObjectARB( m_program );
267 glUseProgramObjectARB( m_program );
269 glEnableVertexAttribArrayARB( c_attr_TexCoord0 );
270 glEnableVertexAttribArrayARB( c_attr_Tangent );
271 glEnableVertexAttribArrayARB( c_attr_Binormal );
273 GlobalOpenGL_debugAssertNoErrors();
275 debug_string( "enable bump" );
276 g_bumpGLSLPass_enabled = true;
280 glUseProgramObjectARB( 0 );
282 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
283 glDisableVertexAttribArrayARB( c_attr_Tangent );
284 glDisableVertexAttribArrayARB( c_attr_Binormal );
286 GlobalOpenGL_debugAssertNoErrors();
288 debug_string( "disable bump" );
289 g_bumpGLSLPass_enabled = false;
292 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
293 Matrix4 world2local( localToWorld );
294 matrix4_affine_invert( world2local );
296 Vector3 localLight( origin );
297 matrix4_transform_point( world2local, localLight );
299 Vector3 localViewer( viewer );
300 matrix4_transform_point( world2local, localViewer );
302 Matrix4 local2light( world2light );
303 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
305 glUniform3fARB( u_view_origin, localViewer.x(), localViewer.y(), localViewer.z() );
306 glUniform3fARB( u_light_origin, localLight.x(), localLight.y(), localLight.z() );
307 glUniform3fARB( u_light_color, colour.x(), colour.y(), colour.z() );
308 glUniform1fARB( u_bump_scale, 1.0 );
309 glUniform1fARB( u_specular_exponent, 32.0 );
311 glActiveTexture( GL_TEXTURE3 );
312 glClientActiveTexture( GL_TEXTURE3 );
314 glMatrixMode( GL_TEXTURE );
315 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
316 glMatrixMode( GL_MODELVIEW );
318 GlobalOpenGL_debugAssertNoErrors();
322 GLSLBumpProgram g_bumpGLSL;
325 class GLSLDepthFillProgram : public GLProgram
328 GLhandleARB m_program;
332 m_program = glCreateProgramObjectARB();
336 StringOutputStream filename( 256 );
337 filename << GlobalRadiant().getDataPath() << "gl/zfill_vp.glsl";
338 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
340 filename << GlobalRadiant().getDataPath() << "gl/zfill_fp.glsl";
341 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
344 GLSLProgram_link( m_program );
345 GLSLProgram_validate( m_program );
347 GlobalOpenGL_debugAssertNoErrors();
351 glDeleteObjectARB( m_program );
356 glUseProgramObjectARB( m_program );
357 GlobalOpenGL_debugAssertNoErrors();
358 debug_string( "enable depthfill" );
359 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().getDataPath() << "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().getDataPath() << "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().getDataPath() << "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().getDataPath() << "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().getDataPath() << "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().getDataPath() << "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();
849 /// \brief A container of Renderable references.
850 /// May contain the same Renderable multiple times, with different transforms.
851 class OpenGLStateBucket
854 struct RenderTransform
856 const Matrix4* m_transform;
857 const OpenGLRenderable *m_renderable;
858 const RendererLight* m_light;
860 RenderTransform( const OpenGLRenderable& renderable, const Matrix4& transform, const RendererLight* light )
861 : m_transform( &transform ), m_renderable( &renderable ), m_light( light ){
865 typedef std::vector<RenderTransform> Renderables;
870 Renderables m_renderables;
876 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const RendererLight* light = 0 ){
877 m_renderables.push_back( RenderTransform( renderable, modelview, light ) );
880 OpenGLState& state(){
884 void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
887 #define LIGHT_SHADER_DEBUG 0
889 #if LIGHT_SHADER_DEBUG
890 typedef std::vector<Shader*> LightDebugShaders;
891 LightDebugShaders g_lightDebugShaders;
894 class OpenGLStateLess
897 bool operator()( const OpenGLState& self, const OpenGLState& other ) const {
898 return OpenGLState_less( self, other );
902 typedef ConstReference<OpenGLState> OpenGLStateReference;
903 typedef std::map<OpenGLStateReference, OpenGLStateBucket*, OpenGLStateLess> OpenGLStates;
904 OpenGLStates g_state_sorted;
906 class OpenGLStateBucketAdd
908 OpenGLStateBucket& m_bucket;
909 const OpenGLRenderable& m_renderable;
910 const Matrix4& m_modelview;
912 using func = void(const RendererLight&);
914 OpenGLStateBucketAdd( OpenGLStateBucket& bucket, const OpenGLRenderable& renderable, const Matrix4& modelview ) :
915 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 using func = void(RendererLight&);
929 CountLights() : m_count( 0 ){
932 void operator()( const RendererLight& light ){
936 std::size_t count() const {
941 class OpenGLShader : public Shader
943 typedef std::list<OpenGLStateBucket*> Passes;
947 ModuleObservers m_observers;
949 OpenGLShader() : m_shader( 0 ), m_used( 0 ){
955 void construct( const char* name );
963 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
970 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const LightList* lights ){
971 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
973 #if LIGHT_SHADER_DEBUG
974 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
977 lights->forEachLight( makeCallback1( counter ) );
978 globalOutputStream() << "count = " << counter.count() << "\n";
979 for ( std::size_t i = 0; i < counter.count(); ++i )
981 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
987 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
989 OpenGLStateBucketAdd add( *( *i ), renderable, modelview );
990 lights->forEachLight(makeCallback( add ) );
996 ( *i )->addRenderable( renderable, modelview );
1001 void incrementUsed(){
1002 if ( ++m_used == 1 && m_shader != 0 ) {
1003 m_shader->SetInUse( true );
1007 void decrementUsed(){
1008 if ( --m_used == 0 && m_shader != 0 ) {
1009 m_shader->SetInUse( false );
1013 bool realised() const {
1014 return m_shader != 0;
1017 void attach( ModuleObserver& observer ){
1021 m_observers.attach( observer );
1024 void detach( ModuleObserver& observer ){
1026 observer.unrealise();
1028 m_observers.detach( observer );
1031 void realise( const CopiedString& name ){
1032 construct( name.c_str() );
1034 if ( m_used != 0 && m_shader != 0 ) {
1035 m_shader->SetInUse( true );
1038 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1040 g_state_sorted.insert( OpenGLStates::value_type( OpenGLStateReference( ( *i )->state() ), *i ) );
1043 m_observers.realise();
1047 m_observers.unrealise();
1049 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1051 g_state_sorted.erase( OpenGLStateReference( ( *i )->state() ) );
1057 qtexture_t& getTexture() const {
1058 ASSERT_NOTNULL( m_shader );
1059 return *m_shader->getTexture();
1062 unsigned int getFlags() const {
1063 ASSERT_NOTNULL( m_shader );
1064 return m_shader->getFlags();
1067 IShader& getShader() const {
1068 ASSERT_NOTNULL( m_shader );
1072 OpenGLState& appendDefaultPass(){
1073 m_passes.push_back( new OpenGLStateBucket );
1074 OpenGLState& state = m_passes.back()->state();
1075 OpenGLState_constructDefault( state );
1081 inline bool lightEnabled( const RendererLight& light, const LightCullable& cullable ){
1082 return cullable.testLight( light );
1085 typedef std::set<RendererLight*> RendererLights;
1087 #define DEBUG_LIGHT_SYNC 0
1089 class LinearLightList : public LightList
1091 LightCullable& m_cullable;
1092 RendererLights& m_allLights;
1093 Callback<void()> m_evaluateChanged;
1095 typedef std::list<RendererLight*> Lights;
1096 mutable Lights m_lights;
1097 mutable bool m_lightsChanged;
1099 LinearLightList( LightCullable& cullable, RendererLights& lights, const Callback<void()>& evaluateChanged ) :
1100 m_cullable( cullable ), m_allLights( lights ), m_evaluateChanged( evaluateChanged ){
1101 m_lightsChanged = true;
1104 void evaluateLights() const {
1105 m_evaluateChanged();
1106 if ( m_lightsChanged ) {
1107 m_lightsChanged = false;
1110 m_cullable.clearLights();
1111 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1113 if ( lightEnabled( *( *i ), m_cullable ) ) {
1114 m_lights.push_back( *i );
1115 m_cullable.insertLight( *( *i ) );
1119 #if ( DEBUG_LIGHT_SYNC )
1123 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1125 if ( lightEnabled( *( *i ), m_cullable ) ) {
1126 lights.push_back( *i );
1130 !std::lexicographical_compare( lights.begin(), lights.end(), m_lights.begin(), m_lights.end() )
1131 && !std::lexicographical_compare( m_lights.begin(), m_lights.end(), lights.begin(), lights.end() ),
1132 "lights out of sync"
1138 void forEachLight( const RendererLightCallback& callback ) const {
1141 for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i )
1143 callback( *( *i ) );
1147 void lightsChanged() const {
1148 m_lightsChanged = true;
1152 inline void setFogState( const OpenGLFogState& state ){
1153 glFogi( GL_FOG_MODE, state.mode );
1154 glFogf( GL_FOG_DENSITY, state.density );
1155 glFogf( GL_FOG_START, state.start );
1156 glFogf( GL_FOG_END, state.end );
1157 glFogi( GL_FOG_INDEX, state.index );
1158 glFogfv( GL_FOG_COLOR, vector4_to_array( state.colour ) );
1161 #define DEBUG_SHADERS 0
1163 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver
1165 class CreateOpenGLShader
1167 OpenGLShaderCache* m_cache;
1169 explicit CreateOpenGLShader( OpenGLShaderCache* cache = 0 )
1173 OpenGLShader* construct( const CopiedString& name ){
1174 OpenGLShader* shader = new OpenGLShader;
1175 if ( m_cache->realised() ) {
1176 shader->realise( name );
1181 void destroy( OpenGLShader* shader ){
1182 if ( m_cache->realised() ) {
1183 shader->unrealise();
1189 typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1191 std::size_t m_unrealised;
1193 bool m_lightingEnabled;
1194 bool m_lightingSupported;
1195 bool m_useShaderLanguage;
1199 : m_shaders( CreateOpenGLShader( this ) ),
1200 m_unrealised( 3 ), // wait until shaders, gl-context and textures are realised before creating any render-states
1201 m_lightingEnabled( true ),
1202 m_lightingSupported( false ),
1203 m_useShaderLanguage( false ),
1204 m_lightsChanged( true ),
1205 m_traverseRenderablesMutex( false ){
1208 ~OpenGLShaderCache(){
1209 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1211 globalOutputStream() << "leaked shader: " << makeQuoted( ( *i ).key.c_str() ) << "\n";
1215 Shader* capture( const char* name ){
1216 ASSERT_MESSAGE( name[0] == '$'
1220 || strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
1222 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1224 return m_shaders.capture( name ).get();
1227 void release( const char *name ){
1229 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1231 m_shaders.release( name );
1233 void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
1234 glMatrixMode( GL_PROJECTION );
1235 glLoadMatrixf( reinterpret_cast<const float*>( &projection ) );
1237 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1240 glMatrixMode( GL_MODELVIEW );
1241 glLoadMatrixf( reinterpret_cast<const float*>( &modelview ) );
1243 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1246 ASSERT_MESSAGE( realised(), "render states are not realised" );
1248 // global settings that are not set in renderstates
1249 glFrontFace( GL_CW );
1250 glCullFace( GL_BACK );
1251 glPolygonOffset( -1, 1 );
1253 const GLubyte pattern[132] = {
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,
1269 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
1271 glPolygonStipple( pattern );
1273 glEnableClientState( GL_VERTEX_ARRAY );
1274 g_vertexArray_enabled = true;
1275 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1277 if ( GlobalOpenGL().GL_1_3() ) {
1278 glActiveTexture( GL_TEXTURE0 );
1279 glClientActiveTexture( GL_TEXTURE0 );
1282 if ( GlobalOpenGL().ARB_shader_objects() ) {
1283 glUseProgramObjectARB( 0 );
1284 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
1285 glDisableVertexAttribArrayARB( c_attr_Tangent );
1286 glDisableVertexAttribArrayARB( c_attr_Binormal );
1289 if ( globalstate & RENDER_TEXTURE ) {
1290 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1291 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
1294 OpenGLState current;
1295 OpenGLState_constructDefault( current );
1296 current.m_sort = OpenGLState::eSortFirst;
1298 // default renderstate settings
1299 glLineStipple( current.m_linestipple_factor, current.m_linestipple_pattern );
1300 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1301 glDisable( GL_LIGHTING );
1302 glDisable( GL_TEXTURE_2D );
1303 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1304 g_texcoordArray_enabled = false;
1305 glDisableClientState( GL_COLOR_ARRAY );
1306 g_colorArray_enabled = false;
1307 glDisableClientState( GL_NORMAL_ARRAY );
1308 g_normalArray_enabled = false;
1309 glDisable( GL_BLEND );
1310 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1311 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1312 glDisable( GL_CULL_FACE );
1313 glShadeModel( GL_FLAT );
1314 glDisable( GL_DEPTH_TEST );
1315 glDepthMask( GL_FALSE );
1316 glDisable( GL_ALPHA_TEST );
1317 glDisable( GL_LINE_STIPPLE );
1318 glDisable( GL_POLYGON_STIPPLE );
1319 glDisable( GL_POLYGON_OFFSET_LINE );
1321 glBindTexture( GL_TEXTURE_2D, 0 );
1322 glColor4f( 1,1,1,1 );
1323 glDepthFunc( GL_LESS );
1324 glAlphaFunc( GL_ALWAYS, 0 );
1328 glHint( GL_FOG_HINT, GL_NICEST );
1329 glDisable( GL_FOG );
1330 setFogState( OpenGLFogState() );
1332 GlobalOpenGL_debugAssertNoErrors();
1334 debug_string( "begin rendering" );
1335 for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
1337 ( *i ).second->render( current, globalstate, viewer );
1339 debug_string( "end rendering" );
1343 if ( --m_unrealised == 0 ) {
1344 if ( lightingSupported() && lightingEnabled() ) {
1345 if ( useShaderLanguage() ) {
1346 g_bumpGLSL.create();
1347 g_depthFillGLSL.create();
1352 g_depthFillARB.create();
1356 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1358 if ( !( *i ).value.empty() ) {
1359 ( *i ).value->realise( i->key );
1366 if ( ++m_unrealised == 1 ) {
1367 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1369 if ( !( *i ).value.empty() ) {
1370 ( *i ).value->unrealise();
1373 if ( GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled() ) {
1374 if ( useShaderLanguage() ) {
1375 g_bumpGLSL.destroy();
1376 g_depthFillGLSL.destroy();
1380 g_bumpARB.destroy();
1381 g_depthFillARB.destroy();
1388 return m_unrealised == 0;
1392 bool lightingEnabled() const {
1393 return m_lightingEnabled;
1396 bool lightingSupported() const {
1397 return m_lightingSupported;
1400 bool useShaderLanguage() const {
1401 return m_useShaderLanguage;
1404 void setLighting( bool supported, bool enabled ){
1405 bool refresh = ( m_lightingSupported && m_lightingEnabled ) != ( supported && enabled );
1409 GlobalShaderSystem().setLightingEnabled( supported && enabled );
1412 m_lightingSupported = supported;
1413 m_lightingEnabled = enabled;
1420 void extensionsInitialised(){
1421 setLighting( GlobalOpenGL().GL_1_3()
1422 && GlobalOpenGL().ARB_vertex_program()
1423 && GlobalOpenGL().ARB_fragment_program()
1424 && GlobalOpenGL().ARB_shader_objects()
1425 && GlobalOpenGL().ARB_vertex_shader()
1426 && GlobalOpenGL().ARB_fragment_shader()
1427 && GlobalOpenGL().ARB_shading_language_100(),
1431 if ( !lightingSupported() ) {
1432 globalOutputStream() << "Lighting mode requires OpenGL features not supported by your graphics drivers:\n";
1433 if ( !GlobalOpenGL().GL_1_3() ) {
1434 globalOutputStream() << " GL version 1.3 or better\n";
1436 if ( !GlobalOpenGL().ARB_vertex_program() ) {
1437 globalOutputStream() << " GL_ARB_vertex_program\n";
1439 if ( !GlobalOpenGL().ARB_fragment_program() ) {
1440 globalOutputStream() << " GL_ARB_fragment_program\n";
1442 if ( !GlobalOpenGL().ARB_shader_objects() ) {
1443 globalOutputStream() << " GL_ARB_shader_objects\n";
1445 if ( !GlobalOpenGL().ARB_vertex_shader() ) {
1446 globalOutputStream() << " GL_ARB_vertex_shader\n";
1448 if ( !GlobalOpenGL().ARB_fragment_shader() ) {
1449 globalOutputStream() << " GL_ARB_fragment_shader\n";
1451 if ( !GlobalOpenGL().ARB_shading_language_100() ) {
1452 globalOutputStream() << " GL_ARB_shading_language_100\n";
1457 void setLightingEnabled( bool enabled ){
1458 setLighting( m_lightingSupported, enabled );
1463 RendererLights m_lights;
1464 bool m_lightsChanged;
1465 typedef std::map<LightCullable*, LinearLightList> LightLists;
1466 LightLists m_lightLists;
1468 const LightList& attach( LightCullable& cullable ){
1469 return ( *m_lightLists.insert( LightLists::value_type( &cullable, LinearLightList( cullable, m_lights, EvaluateChangedCaller( *this ) ) ) ).first ).second;
1472 void detach( LightCullable& cullable ){
1473 m_lightLists.erase( &cullable );
1476 void changed( LightCullable& cullable ){
1477 LightLists::iterator i = m_lightLists.find( &cullable );
1478 ASSERT_MESSAGE( i != m_lightLists.end(), "cullable not attached" );
1479 ( *i ).second.lightsChanged();
1482 void attach( RendererLight& light ){
1483 ASSERT_MESSAGE( m_lights.find( &light ) == m_lights.end(), "light could not be attached" );
1484 m_lights.insert( &light );
1488 void detach( RendererLight& light ){
1489 ASSERT_MESSAGE( m_lights.find( &light ) != m_lights.end(), "light could not be detached" );
1490 m_lights.erase( &light );
1494 void changed( RendererLight& light ){
1495 m_lightsChanged = true;
1498 void evaluateChanged(){
1499 if ( m_lightsChanged ) {
1500 m_lightsChanged = false;
1501 for ( LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i )
1503 ( *i ).second.lightsChanged();
1508 typedef MemberCaller<OpenGLShaderCache, void(), &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1510 typedef std::set<const Renderable*> Renderables;
1511 Renderables m_renderables;
1512 mutable bool m_traverseRenderablesMutex;
1515 void attachRenderable( const Renderable& renderable ){
1516 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "attaching renderable during traversal" );
1517 ASSERT_MESSAGE( m_renderables.find( &renderable ) == m_renderables.end(), "renderable could not be attached" );
1518 m_renderables.insert( &renderable );
1521 void detachRenderable( const Renderable& renderable ){
1522 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "detaching renderable during traversal" );
1523 ASSERT_MESSAGE( m_renderables.find( &renderable ) != m_renderables.end(), "renderable could not be detached" );
1524 m_renderables.erase( &renderable );
1527 void forEachRenderable( const RenderableCallback& callback ) const {
1528 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "for-each during traversal" );
1529 m_traverseRenderablesMutex = true;
1530 for ( Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i )
1532 callback( *( *i ) );
1534 m_traverseRenderablesMutex = false;
1538 static OpenGLShaderCache* g_ShaderCache;
1540 void ShaderCache_extensionsInitialised(){
1541 g_ShaderCache->extensionsInitialised();
1544 void ShaderCache_setBumpEnabled( bool enabled ){
1545 g_ShaderCache->setLightingEnabled( enabled );
1549 Vector3 g_DebugShaderColours[256];
1550 Shader* g_defaultPointLight = 0;
1552 void ShaderCache_Construct(){
1553 g_ShaderCache = new OpenGLShaderCache;
1554 GlobalTexturesCache().attach( *g_ShaderCache );
1555 GlobalShaderSystem().attach( *g_ShaderCache );
1557 if ( g_pGameDescription->mGameType == "doom3" ) {
1558 g_defaultPointLight = g_ShaderCache->capture( "lights/defaultPointLight" );
1559 //Shader* overbright =
1560 g_ShaderCache->capture( "$OVERBRIGHT" );
1562 #if LIGHT_SHADER_DEBUG
1563 for ( std::size_t i = 0; i < 256; ++i )
1565 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1568 g_DebugShaderColours[0] = Vector3( 1, 0, 0 );
1569 g_DebugShaderColours[1] = Vector3( 1, 0.5, 0 );
1570 g_DebugShaderColours[2] = Vector3( 1, 1, 0 );
1571 g_DebugShaderColours[3] = Vector3( 0.5, 1, 0 );
1572 g_DebugShaderColours[4] = Vector3( 0, 1, 0 );
1573 g_DebugShaderColours[5] = Vector3( 0, 1, 0.5 );
1574 g_DebugShaderColours[6] = Vector3( 0, 1, 1 );
1575 g_DebugShaderColours[7] = Vector3( 0, 0.5, 1 );
1576 g_DebugShaderColours[8] = Vector3( 0, 0, 1 );
1577 g_DebugShaderColours[9] = Vector3( 0.5, 0, 1 );
1578 g_DebugShaderColours[10] = Vector3( 1, 0, 1 );
1579 g_DebugShaderColours[11] = Vector3( 1, 0, 0.5 );
1581 g_lightDebugShaders.reserve( 256 );
1582 StringOutputStream buffer( 256 );
1583 for ( std::size_t i = 0; i < 256; ++i )
1585 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1586 g_lightDebugShaders.push_back( g_ShaderCache->capture( buffer.c_str() ) );
1593 void ShaderCache_Destroy(){
1594 if ( g_pGameDescription->mGameType == "doom3" ) {
1595 g_ShaderCache->release( "lights/defaultPointLight" );
1596 g_ShaderCache->release( "$OVERBRIGHT" );
1597 g_defaultPointLight = 0;
1599 #if LIGHT_SHADER_DEBUG
1600 g_lightDebugShaders.clear();
1601 StringOutputStream buffer( 256 );
1602 for ( std::size_t i = 0; i < 256; ++i )
1604 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1605 g_ShaderCache->release( buffer.c_str() );
1610 GlobalShaderSystem().detach( *g_ShaderCache );
1611 GlobalTexturesCache().detach( *g_ShaderCache );
1612 delete g_ShaderCache;
1615 ShaderCache* GetShaderCache(){
1616 return g_ShaderCache;
1619 inline void setTextureState( GLint& current, const GLint& texture, GLenum textureUnit ){
1620 if ( texture != current ) {
1621 glActiveTexture( textureUnit );
1622 glClientActiveTexture( textureUnit );
1623 glBindTexture( GL_TEXTURE_2D, texture );
1624 GlobalOpenGL_debugAssertNoErrors();
1629 inline void setTextureState( GLint& current, const GLint& texture ){
1630 if ( texture != current ) {
1631 glBindTexture( GL_TEXTURE_2D, texture );
1632 GlobalOpenGL_debugAssertNoErrors();
1637 inline void setState( unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag ){
1638 if ( delta & state & flag ) {
1640 GlobalOpenGL_debugAssertNoErrors();
1642 else if ( delta & ~state & flag ) {
1643 glDisable( glflag );
1644 GlobalOpenGL_debugAssertNoErrors();
1648 void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
1649 debug_int( "sort", int(self.m_sort) );
1650 debug_int( "texture", self.m_texture );
1651 debug_int( "state", self.m_state );
1652 debug_int( "address", int(std::size_t( &self ) ) );
1656 if ( self.m_state & RENDER_OVERRIDE ) {
1657 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1660 const unsigned int state = self.m_state & globalstate;
1661 const unsigned int delta = state ^ current.m_state;
1663 GlobalOpenGL_debugAssertNoErrors();
1665 GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0;
1667 if ( program != current.m_program ) {
1668 if ( current.m_program != 0 ) {
1669 current.m_program->disable();
1670 glColor4fv( vector4_to_array( current.m_colour ) );
1671 debug_colour( "cleaning program" );
1674 current.m_program = program;
1676 if ( current.m_program != 0 ) {
1677 current.m_program->enable();
1681 if ( delta & state & RENDER_FILL ) {
1682 //qglPolygonMode (GL_BACK, GL_LINE);
1683 //qglPolygonMode (GL_FRONT, GL_FILL);
1684 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1685 GlobalOpenGL_debugAssertNoErrors();
1687 else if ( delta & ~state & RENDER_FILL ) {
1688 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1689 GlobalOpenGL_debugAssertNoErrors();
1692 setState( state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE );
1694 if ( delta & state & RENDER_LIGHTING ) {
1695 glEnable( GL_LIGHTING );
1696 glEnable( GL_COLOR_MATERIAL );
1697 glEnable( GL_RESCALE_NORMAL );
1698 glEnableClientState( GL_NORMAL_ARRAY );
1699 GlobalOpenGL_debugAssertNoErrors();
1700 g_normalArray_enabled = true;
1702 else if ( delta & ~state & RENDER_LIGHTING ) {
1703 glDisable( GL_LIGHTING );
1704 glDisable( GL_COLOR_MATERIAL );
1705 glDisable( GL_RESCALE_NORMAL );
1706 glDisableClientState( GL_NORMAL_ARRAY );
1707 GlobalOpenGL_debugAssertNoErrors();
1708 g_normalArray_enabled = false;
1711 if ( delta & state & RENDER_TEXTURE ) {
1712 GlobalOpenGL_debugAssertNoErrors();
1714 if ( GlobalOpenGL().GL_1_3() ) {
1715 glActiveTexture( GL_TEXTURE0 );
1716 glClientActiveTexture( GL_TEXTURE0 );
1719 glEnable( GL_TEXTURE_2D );
1721 glColor4f( 1,1,1,self.m_colour[3] );
1722 debug_colour( "setting texture" );
1724 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1725 GlobalOpenGL_debugAssertNoErrors();
1726 g_texcoordArray_enabled = true;
1728 else if ( delta & ~state & RENDER_TEXTURE ) {
1729 if ( GlobalOpenGL().GL_1_3() ) {
1730 glActiveTexture( GL_TEXTURE0 );
1731 glClientActiveTexture( GL_TEXTURE0 );
1734 glDisable( GL_TEXTURE_2D );
1735 glBindTexture( GL_TEXTURE_2D, 0 );
1736 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1738 GlobalOpenGL_debugAssertNoErrors();
1739 g_texcoordArray_enabled = false;
1742 if ( delta & state & RENDER_BLEND ) {
1743 // FIXME: some .TGA are buggy, have a completely empty alpha channel
1744 // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1745 // so I decided using GL_DECAL instead
1746 // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1747 // this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1749 glEnable( GL_BLEND );
1750 if ( GlobalOpenGL().GL_1_3() ) {
1751 glActiveTexture( GL_TEXTURE0 );
1753 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
1754 GlobalOpenGL_debugAssertNoErrors();
1756 else if ( delta & ~state & RENDER_BLEND ) {
1757 glDisable( GL_BLEND );
1758 if ( GlobalOpenGL().GL_1_3() ) {
1759 glActiveTexture( GL_TEXTURE0 );
1761 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1762 GlobalOpenGL_debugAssertNoErrors();
1765 setState( state, delta, RENDER_CULLFACE, GL_CULL_FACE );
1767 if ( delta & state & RENDER_SMOOTH ) {
1768 glShadeModel( GL_SMOOTH );
1769 GlobalOpenGL_debugAssertNoErrors();
1771 else if ( delta & ~state & RENDER_SMOOTH ) {
1772 glShadeModel( GL_FLAT );
1773 GlobalOpenGL_debugAssertNoErrors();
1776 setState( state, delta, RENDER_SCALED, GL_NORMALIZE ); // not GL_RESCALE_NORMAL
1778 setState( state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST );
1780 if ( delta & state & RENDER_DEPTHWRITE ) {
1781 glDepthMask( GL_TRUE );
1784 GLboolean depthEnabled;
1785 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1786 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1788 debug_string( "enabled depth-buffer writing" );
1790 GlobalOpenGL_debugAssertNoErrors();
1792 else if ( delta & ~state & RENDER_DEPTHWRITE ) {
1793 glDepthMask( GL_FALSE );
1796 GLboolean depthEnabled;
1797 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1798 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1800 debug_string( "disabled depth-buffer writing" );
1802 GlobalOpenGL_debugAssertNoErrors();
1805 if ( delta & state & RENDER_COLOURWRITE ) {
1806 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
1807 GlobalOpenGL_debugAssertNoErrors();
1809 else if ( delta & ~state & RENDER_COLOURWRITE ) {
1810 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
1811 GlobalOpenGL_debugAssertNoErrors();
1814 setState( state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST );
1816 if ( delta & state & RENDER_COLOURARRAY ) {
1817 glEnableClientState( GL_COLOR_ARRAY );
1818 GlobalOpenGL_debugAssertNoErrors();
1819 debug_colour( "enabling color_array" );
1820 g_colorArray_enabled = true;
1822 else if ( delta & ~state & RENDER_COLOURARRAY ) {
1823 glDisableClientState( GL_COLOR_ARRAY );
1824 glColor4fv( vector4_to_array( self.m_colour ) );
1825 debug_colour( "cleaning color_array" );
1826 GlobalOpenGL_debugAssertNoErrors();
1827 g_colorArray_enabled = false;
1830 if ( delta & ~state & RENDER_COLOURCHANGE ) {
1831 glColor4fv( vector4_to_array( self.m_colour ) );
1832 GlobalOpenGL_debugAssertNoErrors();
1835 setState( state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE );
1836 setState( state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH );
1838 setState( state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE );
1839 setState( state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH );
1841 setState( state, delta, RENDER_FOG, GL_FOG );
1843 if ( ( state & RENDER_FOG ) != 0 ) {
1844 setFogState( self.m_fog );
1845 GlobalOpenGL_debugAssertNoErrors();
1846 current.m_fog = self.m_fog;
1849 if ( state & RENDER_DEPTHTEST && self.m_depthfunc != current.m_depthfunc ) {
1850 glDepthFunc( self.m_depthfunc );
1851 GlobalOpenGL_debugAssertNoErrors();
1852 current.m_depthfunc = self.m_depthfunc;
1855 if ( state & RENDER_LINESTIPPLE
1856 && ( self.m_linestipple_factor != current.m_linestipple_factor
1857 || self.m_linestipple_pattern != current.m_linestipple_pattern ) ) {
1858 glLineStipple( self.m_linestipple_factor, self.m_linestipple_pattern );
1859 GlobalOpenGL_debugAssertNoErrors();
1860 current.m_linestipple_factor = self.m_linestipple_factor;
1861 current.m_linestipple_pattern = self.m_linestipple_pattern;
1865 if ( state & RENDER_ALPHATEST
1866 && ( self.m_alphafunc != current.m_alphafunc
1867 || self.m_alpharef != current.m_alpharef ) ) {
1868 glAlphaFunc( self.m_alphafunc, self.m_alpharef );
1869 GlobalOpenGL_debugAssertNoErrors();
1870 current.m_alphafunc = self.m_alphafunc;
1871 current.m_alpharef = self.m_alpharef;
1883 //if(state & RENDER_TEXTURE) != 0)
1885 texture0 = self.m_texture;
1886 texture1 = self.m_texture1;
1887 texture2 = self.m_texture2;
1888 texture3 = self.m_texture3;
1889 texture4 = self.m_texture4;
1890 texture5 = self.m_texture5;
1891 texture6 = self.m_texture6;
1892 texture7 = self.m_texture7;
1895 if ( GlobalOpenGL().GL_1_3() ) {
1896 setTextureState( current.m_texture, texture0, GL_TEXTURE0 );
1897 setTextureState( current.m_texture1, texture1, GL_TEXTURE1 );
1898 setTextureState( current.m_texture2, texture2, GL_TEXTURE2 );
1899 setTextureState( current.m_texture3, texture3, GL_TEXTURE3 );
1900 setTextureState( current.m_texture4, texture4, GL_TEXTURE4 );
1901 setTextureState( current.m_texture5, texture5, GL_TEXTURE5 );
1902 setTextureState( current.m_texture6, texture6, GL_TEXTURE6 );
1903 setTextureState( current.m_texture7, texture7, GL_TEXTURE7 );
1907 setTextureState( current.m_texture, texture0 );
1912 if ( state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3] ) {
1913 debug_colour( "setting alpha" );
1914 glColor4f( 1,1,1,self.m_colour[3] );
1915 GlobalOpenGL_debugAssertNoErrors();
1918 if ( !( state & RENDER_TEXTURE )
1919 && ( self.m_colour[0] != current.m_colour[0]
1920 || self.m_colour[1] != current.m_colour[1]
1921 || self.m_colour[2] != current.m_colour[2]
1922 || self.m_colour[3] != current.m_colour[3] ) ) {
1923 glColor4fv( vector4_to_array( self.m_colour ) );
1924 debug_colour( "setting non-texture" );
1925 GlobalOpenGL_debugAssertNoErrors();
1927 current.m_colour = self.m_colour;
1929 if ( state & RENDER_BLEND
1930 && ( self.m_blend_src != current.m_blend_src || self.m_blend_dst != current.m_blend_dst ) ) {
1931 glBlendFunc( self.m_blend_src, self.m_blend_dst );
1932 GlobalOpenGL_debugAssertNoErrors();
1933 current.m_blend_src = self.m_blend_src;
1934 current.m_blend_dst = self.m_blend_dst;
1937 if ( !( state & RENDER_FILL )
1938 && self.m_linewidth != current.m_linewidth ) {
1939 glLineWidth( self.m_linewidth );
1940 GlobalOpenGL_debugAssertNoErrors();
1941 current.m_linewidth = self.m_linewidth;
1944 if ( !( state & RENDER_FILL )
1945 && self.m_pointsize != current.m_pointsize ) {
1946 glPointSize( self.m_pointsize );
1947 GlobalOpenGL_debugAssertNoErrors();
1948 current.m_pointsize = self.m_pointsize;
1951 current.m_state = state;
1953 GlobalOpenGL_debugAssertNoErrors();
1956 void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1957 const Matrix4* transform = 0;
1959 for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
1961 //qglLoadMatrixf(i->m_transform);
1962 if ( !transform || ( transform != ( *i ).m_transform && !matrix4_affine_equal( *transform, *( *i ).m_transform ) ) ) {
1964 transform = ( *i ).m_transform;
1967 glMultMatrixf( reinterpret_cast<const float*>( transform ) );
1968 glFrontFace( ( ( current.m_state & RENDER_CULLFACE ) != 0 && matrix4_handedness( *transform ) == MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW );
1973 if ( current.m_program != 0 && ( *i ).m_light != 0 ) {
1974 const IShader& lightShader = static_cast<OpenGLShader*>( ( *i ).m_light->getShader() )->getShader();
1975 if ( lightShader.firstLayer() != 0 ) {
1976 GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
1977 GLuint attenuation_z = lightShader.lightFalloffImage() != 0
1978 ? lightShader.lightFalloffImage()->texture_number
1979 : static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
1981 setTextureState( current.m_texture3, attenuation_xy, GL_TEXTURE3 );
1982 glActiveTexture( GL_TEXTURE3 );
1983 glBindTexture( GL_TEXTURE_2D, attenuation_xy );
1984 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1985 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
1987 setTextureState( current.m_texture4, attenuation_z, GL_TEXTURE4 );
1988 glActiveTexture( GL_TEXTURE4 );
1989 glBindTexture( GL_TEXTURE_2D, attenuation_z );
1990 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1991 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1994 AABB lightBounds( ( *i ).m_light->aabb() );
1996 Matrix4 world2light( g_matrix4_identity );
1998 if ( ( *i ).m_light->isProjected() ) {
1999 world2light = ( *i ).m_light->projection();
2000 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
2001 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
2003 if ( !( *i ).m_light->isProjected() ) {
2004 matrix4_translate_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
2005 matrix4_scale_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
2006 matrix4_scale_by_vec3( world2light, Vector3( 1.0f / lightBounds.extents.x(), 1.0f / lightBounds.extents.y(), 1.0f / lightBounds.extents.z() ) );
2007 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
2008 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
2011 current.m_program->setParameters( viewer, *( *i ).m_transform, lightBounds.origin + ( *i ).m_light->offset(), ( *i ).m_light->colour(), world2light );
2012 debug_string( "set lightBounds parameters" );
2016 ( *i ).m_renderable->render( current.m_state );
2019 renderables.clear();
2022 void OpenGLStateBucket::render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
2023 if ( ( globalstate & m_state.m_state & RENDER_SCREEN ) != 0 ) {
2024 OpenGLState_apply( m_state, current, globalstate );
2025 debug_colour( "screen fill" );
2027 glMatrixMode( GL_PROJECTION );
2029 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
2031 glMatrixMode( GL_MODELVIEW );
2033 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
2035 glBegin( GL_QUADS );
2036 glVertex3f( -1, -1, 0 );
2037 glVertex3f( 1, -1, 0 );
2038 glVertex3f( 1, 1, 0 );
2039 glVertex3f( -1, 1, 0 );
2042 glMatrixMode( GL_PROJECTION );
2045 glMatrixMode( GL_MODELVIEW );
2048 else if ( !m_renderables.empty() ) {
2049 OpenGLState_apply( m_state, current, globalstate );
2050 Renderables_flush( m_renderables, current, globalstate, viewer );
2055 class OpenGLStateMap : public OpenGLStateLibrary
2057 typedef std::map<CopiedString, OpenGLState> States;
2061 ASSERT_MESSAGE( m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty" );
2064 typedef States::iterator iterator;
2067 return m_states.begin();
2071 return m_states.end();
2074 void getDefaultState( OpenGLState& state ) const {
2075 OpenGLState_constructDefault( state );
2078 void insert( const char* name, const OpenGLState& state ){
2079 bool inserted = m_states.insert( States::value_type( name, state ) ).second;
2080 ASSERT_MESSAGE( inserted, "OpenGLStateMap::insert: " << name << " already exists" );
2083 void erase( const char* name ){
2084 std::size_t count = m_states.erase( name );
2085 ASSERT_MESSAGE( count == 1, "OpenGLStateMap::erase: " << name << " does not exist" );
2088 iterator find( const char* name ){
2089 return m_states.find( name );
2093 OpenGLStateMap* g_openglStates = 0;
2095 inline GLenum convertBlendFactor( BlendFactor factor ){
2102 case BLEND_SRC_COLOUR:
2103 return GL_SRC_COLOR;
2104 case BLEND_ONE_MINUS_SRC_COLOUR:
2105 return GL_ONE_MINUS_SRC_COLOR;
2106 case BLEND_SRC_ALPHA:
2107 return GL_SRC_ALPHA;
2108 case BLEND_ONE_MINUS_SRC_ALPHA:
2109 return GL_ONE_MINUS_SRC_ALPHA;
2110 case BLEND_DST_COLOUR:
2111 return GL_DST_COLOR;
2112 case BLEND_ONE_MINUS_DST_COLOUR:
2113 return GL_ONE_MINUS_DST_COLOR;
2114 case BLEND_DST_ALPHA:
2115 return GL_DST_ALPHA;
2116 case BLEND_ONE_MINUS_DST_ALPHA:
2117 return GL_ONE_MINUS_DST_ALPHA;
2118 case BLEND_SRC_ALPHA_SATURATE:
2119 return GL_SRC_ALPHA_SATURATE;
2124 /// \todo Define special-case shaders in a data file.
2125 void OpenGLShader::construct( const char* name ){
2126 OpenGLState& state = appendDefaultPass();
2130 sscanf( name, "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2131 state.m_colour[3] = 1.0f;
2132 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2133 state.m_sort = OpenGLState::eSortFullbright;
2137 sscanf( name, "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2138 state.m_colour[3] = 0.5f;
2139 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_BLEND;
2140 state.m_sort = OpenGLState::eSortTranslucent;
2144 sscanf( name, "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2145 state.m_colour[3] = 1;
2146 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2147 state.m_sort = OpenGLState::eSortFullbright;
2148 state.m_depthfunc = GL_LESS;
2149 state.m_linewidth = 1;
2150 state.m_pointsize = 1;
2155 OpenGLStateMap::iterator i = g_openglStates->find( name );
2156 if ( i != g_openglStates->end() )
2158 state = ( *i ).second;
2163 if ( string_equal( name + 1, "POINT" ) ) {
2164 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2165 state.m_sort = OpenGLState::eSortControlFirst;
2166 state.m_pointsize = 4;
2168 else if ( string_equal( name + 1, "SELPOINT" ) ) {
2169 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2170 state.m_sort = OpenGLState::eSortControlFirst + 1;
2171 state.m_pointsize = 4;
2173 else if ( string_equal( name + 1, "BIGPOINT" ) ) {
2174 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2175 state.m_sort = OpenGLState::eSortControlFirst;
2176 state.m_pointsize = 6;
2178 else if ( string_equal( name + 1, "PIVOT" ) ) {
2179 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
2180 state.m_sort = OpenGLState::eSortGUI1;
2181 state.m_linewidth = 2;
2182 state.m_depthfunc = GL_LEQUAL;
2184 OpenGLState& hiddenLine = appendDefaultPass();
2185 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
2186 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2187 hiddenLine.m_linewidth = 2;
2188 hiddenLine.m_depthfunc = GL_GREATER;
2190 else if ( string_equal( name + 1, "LATTICE" ) ) {
2191 state.m_colour[0] = 1;
2192 state.m_colour[1] = 0.5;
2193 state.m_colour[2] = 0;
2194 state.m_colour[3] = 1;
2195 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2196 state.m_sort = OpenGLState::eSortControlFirst;
2198 else if ( string_equal( name + 1, "WIREFRAME" ) ) {
2199 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2200 state.m_sort = OpenGLState::eSortFullbright;
2202 else if ( string_equal( name + 1, "CAM_HIGHLIGHT" ) ) {
2203 state.m_colour[0] = g_camwindow_globals.color_selbrushes3d[0];
2204 state.m_colour[1] = g_camwindow_globals.color_selbrushes3d[1];
2205 state.m_colour[2] = g_camwindow_globals.color_selbrushes3d[2];
2206 state.m_colour[3] = 0.3f;
2207 state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2208 state.m_sort = OpenGLState::eSortHighlight;
2209 state.m_depthfunc = GL_LEQUAL;
2211 else if ( string_equal( name + 1, "CAM_OVERLAY" ) ) {
2213 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2214 state.m_sort = OpenGLState::eSortOverlayFirst;
2216 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2217 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2218 state.m_depthfunc = GL_LEQUAL;
2220 OpenGLState& hiddenLine = appendDefaultPass();
2221 hiddenLine.m_colour[0] = 0.75;
2222 hiddenLine.m_colour[1] = 0.75;
2223 hiddenLine.m_colour[2] = 0.75;
2224 hiddenLine.m_colour[3] = 1;
2225 hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE | RENDER_LINESTIPPLE;
2226 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2227 hiddenLine.m_depthfunc = GL_GREATER;
2228 hiddenLine.m_linestipple_factor = 2;
2231 else if ( string_equal( name + 1, "XY_OVERLAY" ) ) {
2232 state.m_colour[0] = g_xywindow_globals.color_selbrushes[0];
2233 state.m_colour[1] = g_xywindow_globals.color_selbrushes[1];
2234 state.m_colour[2] = g_xywindow_globals.color_selbrushes[2];
2235 state.m_colour[3] = 1;
2236 state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
2237 state.m_sort = OpenGLState::eSortOverlayFirst;
2238 state.m_linewidth = 2;
2239 state.m_linestipple_factor = 3;
2241 else if ( string_equal( name + 1, "DEBUG_CLIPPED" ) ) {
2242 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2243 state.m_sort = OpenGLState::eSortLast;
2245 else if ( string_equal( name + 1, "POINTFILE" ) ) {
2246 state.m_colour[0] = 1;
2247 state.m_colour[1] = 0;
2248 state.m_colour[2] = 0;
2249 state.m_colour[3] = 1;
2250 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2251 state.m_sort = OpenGLState::eSortFullbright;
2252 state.m_linewidth = 4;
2254 else if ( string_equal( name + 1, "LIGHT_SPHERE" ) ) {
2255 state.m_colour[0] = .15f * .95f;
2256 state.m_colour[1] = .15f * .95f;
2257 state.m_colour[2] = .15f * .95f;
2258 state.m_colour[3] = 1;
2259 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2260 state.m_blend_src = GL_ONE;
2261 state.m_blend_dst = GL_ONE;
2262 state.m_sort = OpenGLState::eSortTranslucent;
2264 else if ( string_equal( name + 1, "Q3MAP2_LIGHT_SPHERE" ) ) {
2265 state.m_colour[0] = .05f;
2266 state.m_colour[1] = .05f;
2267 state.m_colour[2] = .05f;
2268 state.m_colour[3] = 1;
2269 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
2270 state.m_blend_src = GL_ONE;
2271 state.m_blend_dst = GL_ONE;
2272 state.m_sort = OpenGLState::eSortTranslucent;
2274 else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
2276 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2277 state.m_sort = OpenGLState::eSortOverlayFirst;
2279 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2280 state.m_sort = OpenGLState::eSortGUI1;
2281 state.m_depthfunc = GL_LEQUAL;
2283 OpenGLState& hiddenLine = appendDefaultPass();
2284 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_LINESTIPPLE;
2285 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2286 hiddenLine.m_depthfunc = GL_GREATER;
2289 else if ( string_equal( name + 1, "FLATSHADE_OVERLAY" ) ) {
2290 state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2291 state.m_sort = OpenGLState::eSortGUI1;
2292 state.m_depthfunc = GL_LEQUAL;
2294 OpenGLState& hiddenLine = appendDefaultPass();
2295 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;
2296 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2297 hiddenLine.m_depthfunc = GL_GREATER;
2299 else if ( string_equal( name + 1, "CLIPPER_OVERLAY" ) ) {
2300 state.m_colour[0] = g_xywindow_globals.color_clipper[0];
2301 state.m_colour[1] = g_xywindow_globals.color_clipper[1];
2302 state.m_colour[2] = g_xywindow_globals.color_clipper[2];
2303 state.m_colour[3] = 1;
2304 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE;
2305 state.m_sort = OpenGLState::eSortOverlayFirst;
2307 else if ( string_equal( name + 1, "OVERBRIGHT" ) ) {
2308 const float lightScale = 2;
2309 state.m_colour[0] = lightScale * 0.5f;
2310 state.m_colour[1] = lightScale * 0.5f;
2311 state.m_colour[2] = lightScale * 0.5f;
2312 state.m_colour[3] = 0.5;
2313 state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN;
2314 state.m_sort = OpenGLState::eSortOverbrighten;
2315 state.m_blend_src = GL_DST_COLOR;
2316 state.m_blend_dst = GL_SRC_COLOR;
2320 // default to something recognisable.. =)
2321 ERROR_MESSAGE( "hardcoded renderstate not found" );
2322 state.m_colour[0] = 1;
2323 state.m_colour[1] = 0;
2324 state.m_colour[2] = 1;
2325 state.m_colour[3] = 1;
2326 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2327 state.m_sort = OpenGLState::eSortFirst;
2331 // construction from IShader
2332 m_shader = QERApp_Shader_ForName( name );
2334 if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && m_shader->getBump()->texture_number != 0 ) { // is a bump shader
2335 state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM;
2336 state.m_colour[0] = 0;
2337 state.m_colour[1] = 0;
2338 state.m_colour[2] = 0;
2339 state.m_colour[3] = 1;
2340 state.m_sort = OpenGLState::eSortOpaque;
2342 if ( g_ShaderCache->useShaderLanguage() ) {
2343 state.m_program = &g_depthFillGLSL;
2347 state.m_program = &g_depthFillARB;
2350 OpenGLState& bumpPass = appendDefaultPass();
2351 bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
2352 bumpPass.m_texture1 = m_shader->getBump()->texture_number;
2353 bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
2355 bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2357 if ( g_ShaderCache->useShaderLanguage() ) {
2358 bumpPass.m_state |= RENDER_LIGHTING;
2359 bumpPass.m_program = &g_bumpGLSL;
2363 bumpPass.m_program = &g_bumpARB;
2366 bumpPass.m_depthfunc = GL_LEQUAL;
2367 bumpPass.m_sort = OpenGLState::eSortMultiFirst;
2368 bumpPass.m_blend_src = GL_ONE;
2369 bumpPass.m_blend_dst = GL_ONE;
2373 state.m_texture = m_shader->getTexture()->texture_number;
2375 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH;
2376 if ( ( m_shader->getFlags() & QER_CULL ) != 0 ) {
2377 if ( m_shader->getCull() == IShader::eCullBack ) {
2378 state.m_state |= RENDER_CULLFACE;
2383 state.m_state |= RENDER_CULLFACE;
2385 if ( ( m_shader->getFlags() & QER_ALPHATEST ) != 0 ) {
2386 state.m_state |= RENDER_ALPHATEST;
2387 IShader::EAlphaFunc alphafunc;
2388 m_shader->getAlphaFunc( &alphafunc, &state.m_alpharef );
2389 switch ( alphafunc )
2391 case IShader::eAlways:
2392 state.m_alphafunc = GL_ALWAYS;
2394 case IShader::eEqual:
2395 state.m_alphafunc = GL_EQUAL;
2397 case IShader::eLess:
2398 state.m_alphafunc = GL_LESS;
2400 case IShader::eGreater:
2401 state.m_alphafunc = GL_GREATER;
2403 case IShader::eLEqual:
2404 state.m_alphafunc = GL_LEQUAL;
2406 case IShader::eGEqual:
2407 state.m_alphafunc = GL_GEQUAL;
2411 reinterpret_cast<Vector3&>( state.m_colour ) = m_shader->getTexture()->color;
2412 state.m_colour[3] = 1.0f;
2414 if ( ( m_shader->getFlags() & QER_TRANS ) != 0 ) {
2415 state.m_state |= RENDER_BLEND;
2416 state.m_colour[3] = m_shader->getTrans();
2417 state.m_sort = OpenGLState::eSortTranslucent;
2418 BlendFunc blendFunc = m_shader->getBlendFunc();
2419 state.m_blend_src = convertBlendFactor( blendFunc.m_src );
2420 state.m_blend_dst = convertBlendFactor( blendFunc.m_dst );
2421 state.m_depthfunc = GL_LEQUAL;
2422 if ( state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA ) {
2423 state.m_state |= RENDER_DEPTHWRITE;
2428 state.m_state |= RENDER_DEPTHWRITE;
2429 state.m_sort = OpenGLState::eSortFullbright;
2436 #include "modulesystem/singletonmodule.h"
2437 #include "modulesystem/moduleregistry.h"
2439 class OpenGLStateLibraryAPI
2441 OpenGLStateMap m_stateMap;
2443 typedef OpenGLStateLibrary Type;
2445 STRING_CONSTANT( Name, "*" );
2447 OpenGLStateLibraryAPI(){
2448 g_openglStates = &m_stateMap;
2451 ~OpenGLStateLibraryAPI(){
2455 OpenGLStateLibrary* getTable(){
2460 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2461 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2462 StaticRegisterModule staticRegisterOpenGLStateLibrary( StaticOpenGLStateLibraryModule::instance() );
2464 class ShaderCacheDependencies : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef
2467 ShaderCacheDependencies() :
2468 GlobalShadersModuleRef( GlobalRadiant().getRequiredGameDescriptionKeyValue( "shaders" ) ){
2472 class ShaderCacheAPI
2474 ShaderCache* m_shaderCache;
2476 typedef ShaderCache Type;
2478 STRING_CONSTANT( Name, "*" );
2481 ShaderCache_Construct();
2483 m_shaderCache = GetShaderCache();
2487 ShaderCache_Destroy();
2490 ShaderCache* getTable(){
2491 return m_shaderCache;
2495 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2496 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2497 StaticRegisterModule staticRegisterShaderCache( StaticShaderCacheModule::instance() );