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 );
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().getAppPath() << "gl/lighting_DBS_omni_vp.glsl";
229 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
231 filename << GlobalRadiant().getAppPath() << "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().getAppPath() << "gl/zfill_vp.glsl";
338 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
340 filename << GlobalRadiant().getAppPath() << "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 );
355 glUseProgramObjectARB( m_program );
356 GlobalOpenGL_debugAssertNoErrors();
357 debug_string( "enable depthfill" );
358 g_depthfillPass_enabled = true;
361 glUseProgramObjectARB( 0 );
362 GlobalOpenGL_debugAssertNoErrors();
363 debug_string( "disable depthfill" );
364 g_depthfillPass_enabled = false;
366 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
370 GLSLDepthFillProgram g_depthFillGLSL;
375 void createProgram( const char* filename, GLenum type ){
376 std::size_t size = file_size( filename );
377 FileInputStream file( filename );
378 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
379 Array<GLcharARB> buffer( size );
380 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
382 glProgramStringARB( type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei( size ), buffer.data() );
384 if ( GL_INVALID_OPERATION == glGetError() ) {
386 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
387 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_ARB );
389 globalErrorStream() << reinterpret_cast<const char*>( filename ) << ":" << errPos << "\n" << reinterpret_cast<const char*>( errString );
391 ERROR_MESSAGE( "error in gl program" );
395 class ARBBumpProgram : public GLProgram
398 GLuint m_vertex_program;
399 GLuint m_fragment_program;
402 glEnable( GL_VERTEX_PROGRAM_ARB );
403 glEnable( GL_FRAGMENT_PROGRAM_ARB );
406 glGenProgramsARB( 1, &m_vertex_program );
407 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
408 StringOutputStream filename( 256 );
409 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.glp";
410 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
412 glGenProgramsARB( 1, &m_fragment_program );
413 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
415 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glp";
416 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
419 glDisable( GL_VERTEX_PROGRAM_ARB );
420 glDisable( GL_FRAGMENT_PROGRAM_ARB );
422 GlobalOpenGL_debugAssertNoErrors();
426 glDeleteProgramsARB( 1, &m_vertex_program );
427 glDeleteProgramsARB( 1, &m_fragment_program );
428 GlobalOpenGL_debugAssertNoErrors();
432 glEnable( GL_VERTEX_PROGRAM_ARB );
433 glEnable( GL_FRAGMENT_PROGRAM_ARB );
434 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
435 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
437 glEnableVertexAttribArrayARB( 8 );
438 glEnableVertexAttribArrayARB( 9 );
439 glEnableVertexAttribArrayARB( 10 );
440 glEnableVertexAttribArrayARB( 11 );
442 GlobalOpenGL_debugAssertNoErrors();
446 glDisable( GL_VERTEX_PROGRAM_ARB );
447 glDisable( GL_FRAGMENT_PROGRAM_ARB );
449 glDisableVertexAttribArrayARB( 8 );
450 glDisableVertexAttribArrayARB( 9 );
451 glDisableVertexAttribArrayARB( 10 );
452 glDisableVertexAttribArrayARB( 11 );
454 GlobalOpenGL_debugAssertNoErrors();
457 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
458 Matrix4 world2local( localToWorld );
459 matrix4_affine_invert( world2local );
461 Vector3 localLight( origin );
462 matrix4_transform_point( world2local, localLight );
464 Vector3 localViewer( viewer );
465 matrix4_transform_point( world2local, localViewer );
467 Matrix4 local2light( world2light );
468 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
471 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0 );
474 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1 );
477 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0 );
480 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0 );
483 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0 );
486 glActiveTexture( GL_TEXTURE3 );
487 glClientActiveTexture( GL_TEXTURE3 );
489 glMatrixMode( GL_TEXTURE );
490 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
491 glMatrixMode( GL_MODELVIEW );
493 GlobalOpenGL_debugAssertNoErrors();
497 class ARBDepthFillProgram : public GLProgram
500 GLuint m_vertex_program;
501 GLuint m_fragment_program;
504 glEnable( GL_VERTEX_PROGRAM_ARB );
505 glEnable( GL_FRAGMENT_PROGRAM_ARB );
508 glGenProgramsARB( 1, &m_vertex_program );
509 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
510 StringOutputStream filename( 256 );
511 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glp";
512 createProgram( filename.c_str(), GL_VERTEX_PROGRAM_ARB );
514 glGenProgramsARB( 1, &m_fragment_program );
515 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
517 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glp";
518 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
521 glDisable( GL_VERTEX_PROGRAM_ARB );
522 glDisable( GL_FRAGMENT_PROGRAM_ARB );
524 GlobalOpenGL_debugAssertNoErrors();
528 glDeleteProgramsARB( 1, &m_vertex_program );
529 glDeleteProgramsARB( 1, &m_fragment_program );
530 GlobalOpenGL_debugAssertNoErrors();
534 glEnable( GL_VERTEX_PROGRAM_ARB );
535 glEnable( GL_FRAGMENT_PROGRAM_ARB );
536 glBindProgramARB( GL_VERTEX_PROGRAM_ARB, m_vertex_program );
537 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
539 GlobalOpenGL_debugAssertNoErrors();
543 glDisable( GL_VERTEX_PROGRAM_ARB );
544 glDisable( GL_FRAGMENT_PROGRAM_ARB );
546 GlobalOpenGL_debugAssertNoErrors();
549 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
553 ARBBumpProgram g_bumpARB;
554 ARBDepthFillProgram g_depthFillARB;
558 // NV20 path (unfinished)
560 void createProgram( GLint program, const char* filename, GLenum type ){
561 std::size_t size = file_size( filename );
562 FileInputStream file( filename );
563 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
564 Array<GLubyte> buffer( size );
565 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
567 glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
569 if ( GL_INVALID_OPERATION == glGetError() ) {
571 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
572 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
574 globalErrorStream() << filename << ":" << errPos << "\n" << errString;
576 ERROR_MESSAGE( "error in gl program" );
580 GLuint m_vertex_program;
581 GLuint m_fragment_program;
582 qtexture_t* g_cube = 0;
583 qtexture_t* g_specular_lookup = 0;
584 qtexture_t* g_attenuation_xy = 0;
585 qtexture_t* g_attenuation_z = 0;
587 void createVertexProgram(){
589 glGenProgramsNV( 1, &m_vertex_program );
590 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
591 StringOutputStream filename( 256 );
592 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.nv30";
593 createProgram( m_vertex_program, filename.c_str(), GL_VERTEX_PROGRAM_NV );
595 glGenProgramsNV( 1, &m_fragment_program );
596 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
598 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.nv30";
599 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
602 g_cube = GlobalTexturesCache().capture( "generated/cube" );
603 g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
605 g_attenuation_xy = GlobalTexturesCache().capture( "lights/squarelight1" );
606 glActiveTexture( GL_TEXTURE0 );
607 glBindTexture( GL_TEXTURE_2D, g_attenuation_xy->texture_number );
608 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
609 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
611 g_attenuation_z = GlobalTexturesCache().capture( "lights/squarelight1a" );
612 glActiveTexture( GL_TEXTURE0 );
613 glBindTexture( GL_TEXTURE_2D, g_attenuation_z->texture_number );
614 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
615 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
617 GlobalOpenGL_debugAssertNoErrors();
620 void destroyVertexProgram(){
621 glDeleteProgramsNV( 1, &m_vertex_program );
622 glDeleteProgramsNV( 1, &m_fragment_program );
623 GlobalOpenGL_debugAssertNoErrors();
625 GlobalTexturesCache().release( g_cube );
626 GlobalTexturesCache().release( g_specular_lookup );
627 GlobalTexturesCache().release( g_attenuation_xy );
628 GlobalTexturesCache().release( g_attenuation_z );
631 bool g_vertexProgram_enabled = false;
633 void enableVertexProgram(){
634 //set up the register combiners
635 //two general combiners
636 glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
638 //combiner 0 does tex0+tex1 -> spare0
639 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB,
640 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
641 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
642 GL_UNSIGNED_INVERT_NV, GL_RGB );
643 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB,
644 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
645 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
646 GL_UNSIGNED_INVERT_NV, GL_RGB );
647 glCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV,
648 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
650 //combiner 1 does tex2 dot tex3 -> spare1
651 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE2_ARB,
652 GL_EXPAND_NORMAL_NV, GL_RGB );
653 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE3_ARB,
654 GL_EXPAND_NORMAL_NV, GL_RGB );
655 glCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
656 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
660 //final combiner outputs (1-spare0)*constant color 0*spare1
661 //do constant color 0*spare1 in the EF multiplier
662 glFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
663 glFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
665 //now do (1-spare0)*EF
666 glFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
667 glFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
668 glFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
669 glFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
671 glEnable( GL_VERTEX_PROGRAM_NV );
672 glEnable( GL_REGISTER_COMBINERS_NV );
673 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
674 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
676 glActiveTexture( GL_TEXTURE0 );
677 glEnable( GL_TEXTURE_2D );
678 glActiveTexture( GL_TEXTURE1 );
679 glEnable( GL_TEXTURE_1D );
680 glActiveTexture( GL_TEXTURE2 );
681 glEnable( GL_TEXTURE_2D );
682 glActiveTexture( GL_TEXTURE3 );
683 glEnable( GL_TEXTURE_2D );
685 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
686 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
687 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
688 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
690 GlobalOpenGL_debugAssertNoErrors();
691 g_vertexProgram_enabled = true;
694 void disableVertexProgram(){
695 glDisable( GL_VERTEX_PROGRAM_NV );
696 glDisable( GL_REGISTER_COMBINERS_NV );
698 glActiveTexture( GL_TEXTURE0 );
699 glDisable( GL_TEXTURE_2D );
700 glActiveTexture( GL_TEXTURE1 );
701 glDisable( GL_TEXTURE_1D );
702 glActiveTexture( GL_TEXTURE2 );
703 glDisable( GL_TEXTURE_2D );
704 glActiveTexture( GL_TEXTURE3 );
705 glDisable( GL_TEXTURE_2D );
707 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
708 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
709 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
710 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
712 GlobalOpenGL_debugAssertNoErrors();
713 g_vertexProgram_enabled = false;
719 const GLubyte* m_string;
720 const GLint m_length;
721 GLstringNV( const char* string ) : m_string( reinterpret_cast<const GLubyte*>( string ) ), m_length( GLint( string_length( string ) ) ){
725 GLstringNV g_light_origin( "light_origin" );
726 GLstringNV g_view_origin( "view_origin" );
727 GLstringNV g_light_color( "light_color" );
728 GLstringNV g_bumpGLSL_scale( "bump_scale" );
729 GLstringNV g_specular_exponent( "specular_exponent" );
731 void setVertexProgramEnvironment( const Vector3& localViewer ){
732 Matrix4 local2light( g_matrix4_identity );
733 matrix4_translate_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
734 matrix4_scale_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
735 matrix4_scale_by_vec3( local2light, Vector3( 1.0 / 512.0, 1.0 / 512.0, 1.0 / 512.0 ) );
736 matrix4_translate_by_vec3( local2light, vector3_negated( localViewer ) );
738 glActiveTexture( GL_TEXTURE3 );
739 glClientActiveTexture( GL_TEXTURE3 );
741 glMatrixMode( GL_TEXTURE );
742 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
743 glMatrixMode( GL_MODELVIEW );
745 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV );
746 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 4, GL_TEXTURE0_ARB, GL_IDENTITY_NV );
749 //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
752 glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
755 glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
758 //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
761 //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
763 GlobalOpenGL_debugAssertNoErrors();
769 bool g_vertexArray_enabled = false;
770 bool g_normalArray_enabled = false;
771 bool g_texcoordArray_enabled = false;
772 bool g_colorArray_enabled = false;
774 inline bool OpenGLState_less( const OpenGLState& self, const OpenGLState& other ){
775 //! Sort by sort-order override.
776 if ( self.m_sort != other.m_sort ) {
777 return self.m_sort < other.m_sort;
779 //! Sort by texture handle.
780 if ( self.m_texture != other.m_texture ) {
781 return self.m_texture < other.m_texture;
783 if ( self.m_texture1 != other.m_texture1 ) {
784 return self.m_texture1 < other.m_texture1;
786 if ( self.m_texture2 != other.m_texture2 ) {
787 return self.m_texture2 < other.m_texture2;
789 if ( self.m_texture3 != other.m_texture3 ) {
790 return self.m_texture3 < other.m_texture3;
792 if ( self.m_texture4 != other.m_texture4 ) {
793 return self.m_texture4 < other.m_texture4;
795 if ( self.m_texture5 != other.m_texture5 ) {
796 return self.m_texture5 < other.m_texture5;
798 if ( self.m_texture6 != other.m_texture6 ) {
799 return self.m_texture6 < other.m_texture6;
801 if ( self.m_texture7 != other.m_texture7 ) {
802 return self.m_texture7 < other.m_texture7;
804 //! Sort by state bit-vector.
805 if ( self.m_state != other.m_state ) {
806 return self.m_state < other.m_state;
808 //! Comparing address makes sure states are never equal.
809 return &self < &other;
812 void OpenGLState_constructDefault( OpenGLState& state ){
813 state.m_state = RENDER_DEFAULT;
816 state.m_texture1 = 0;
817 state.m_texture2 = 0;
818 state.m_texture3 = 0;
819 state.m_texture4 = 0;
820 state.m_texture5 = 0;
821 state.m_texture6 = 0;
822 state.m_texture7 = 0;
824 state.m_colour[0] = 1;
825 state.m_colour[1] = 1;
826 state.m_colour[2] = 1;
827 state.m_colour[3] = 1;
829 state.m_depthfunc = GL_LESS;
831 state.m_blend_src = GL_SRC_ALPHA;
832 state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
834 state.m_alphafunc = GL_ALWAYS;
835 state.m_alpharef = 0;
837 state.m_linewidth = 1;
838 state.m_pointsize = 1;
840 state.m_linestipple_factor = 1;
841 state.m_linestipple_pattern = 0xaaaa;
843 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;
875 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const RendererLight* light = 0 ){
876 m_renderables.push_back( RenderTransform( renderable, modelview, light ) );
879 OpenGLState& state(){
883 void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
886 #define LIGHT_SHADER_DEBUG 0
888 #if LIGHT_SHADER_DEBUG
889 typedef std::vector<Shader*> LightDebugShaders;
890 LightDebugShaders g_lightDebugShaders;
893 class OpenGLStateLess
896 bool operator()( const OpenGLState& self, const OpenGLState& other ) const {
897 return OpenGLState_less( self, other );
901 typedef ConstReference<OpenGLState> OpenGLStateReference;
902 typedef std::map<OpenGLStateReference, OpenGLStateBucket*, OpenGLStateLess> OpenGLStates;
903 OpenGLStates g_state_sorted;
905 class OpenGLStateBucketAdd
907 OpenGLStateBucket& m_bucket;
908 const OpenGLRenderable& m_renderable;
909 const Matrix4& m_modelview;
911 typedef const RendererLight& first_argument_type;
913 OpenGLStateBucketAdd( OpenGLStateBucket& bucket, const OpenGLRenderable& renderable, const Matrix4& modelview ) :
914 m_bucket( bucket ), m_renderable( renderable ), m_modelview( modelview ){
916 void operator()( const RendererLight& light ){
917 m_bucket.addRenderable( m_renderable, m_modelview, &light );
925 typedef RendererLight& first_argument_type;
927 CountLights() : m_count( 0 ){
929 void operator()( const RendererLight& light ){
932 std::size_t count() const {
937 class OpenGLShader : public Shader
939 typedef std::list<OpenGLStateBucket*> Passes;
943 ModuleObservers m_observers;
945 OpenGLShader() : m_shader( 0 ), m_used( 0 ){
949 void construct( const char* name );
956 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
962 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const LightList* lights ){
963 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
965 #if LIGHT_SHADER_DEBUG
966 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
969 lights->forEachLight( makeCallback1( counter ) );
970 globalOutputStream() << "count = " << counter.count() << "\n";
971 for ( std::size_t i = 0; i < counter.count(); ++i )
973 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
979 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
981 OpenGLStateBucketAdd add( *( *i ), renderable, modelview );
982 lights->forEachLight( makeCallback1( add ) );
988 ( *i )->addRenderable( renderable, modelview );
992 void incrementUsed(){
993 if ( ++m_used == 1 && m_shader != 0 ) {
994 m_shader->SetInUse( true );
997 void decrementUsed(){
998 if ( --m_used == 0 && m_shader != 0 ) {
999 m_shader->SetInUse( false );
1002 bool realised() const {
1003 return m_shader != 0;
1005 void attach( ModuleObserver& observer ){
1009 m_observers.attach( observer );
1011 void detach( ModuleObserver& observer ){
1013 observer.unrealise();
1015 m_observers.detach( observer );
1017 void realise( const CopiedString& name ){
1018 construct( name.c_str() );
1020 if ( m_used != 0 && m_shader != 0 ) {
1021 m_shader->SetInUse( true );
1024 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1026 g_state_sorted.insert( OpenGLStates::value_type( OpenGLStateReference( ( *i )->state() ), *i ) );
1029 m_observers.realise();
1032 m_observers.unrealise();
1034 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1036 g_state_sorted.erase( OpenGLStateReference( ( *i )->state() ) );
1041 qtexture_t& getTexture() const {
1042 ASSERT_NOTNULL( m_shader );
1043 return *m_shader->getTexture();
1045 unsigned int getFlags() const {
1046 ASSERT_NOTNULL( m_shader );
1047 return m_shader->getFlags();
1049 IShader& getShader() const {
1050 ASSERT_NOTNULL( m_shader );
1053 OpenGLState& appendDefaultPass(){
1054 m_passes.push_back( new OpenGLStateBucket );
1055 OpenGLState& state = m_passes.back()->state();
1056 OpenGLState_constructDefault( state );
1062 inline bool lightEnabled( const RendererLight& light, const LightCullable& cullable ){
1063 return cullable.testLight( light );
1066 typedef std::set<RendererLight*> RendererLights;
1068 #define DEBUG_LIGHT_SYNC 0
1070 class LinearLightList : public LightList
1072 LightCullable& m_cullable;
1073 RendererLights& m_allLights;
1074 Callback m_evaluateChanged;
1076 typedef std::list<RendererLight*> Lights;
1077 mutable Lights m_lights;
1078 mutable bool m_lightsChanged;
1080 LinearLightList( LightCullable& cullable, RendererLights& lights, const Callback& evaluateChanged ) :
1081 m_cullable( cullable ), m_allLights( lights ), m_evaluateChanged( evaluateChanged ){
1082 m_lightsChanged = true;
1084 void evaluateLights() const {
1085 m_evaluateChanged();
1086 if ( m_lightsChanged ) {
1087 m_lightsChanged = false;
1090 m_cullable.clearLights();
1091 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1093 if ( lightEnabled( *( *i ), m_cullable ) ) {
1094 m_lights.push_back( *i );
1095 m_cullable.insertLight( *( *i ) );
1099 #if ( DEBUG_LIGHT_SYNC )
1103 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1105 if ( lightEnabled( *( *i ), m_cullable ) ) {
1106 lights.push_back( *i );
1110 !std::lexicographical_compare( lights.begin(), lights.end(), m_lights.begin(), m_lights.end() )
1111 && !std::lexicographical_compare( m_lights.begin(), m_lights.end(), lights.begin(), lights.end() ),
1112 "lights out of sync"
1117 void forEachLight( const RendererLightCallback& callback ) const {
1120 for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i )
1122 callback( *( *i ) );
1125 void lightsChanged() const {
1126 m_lightsChanged = true;
1130 inline void setFogState( const OpenGLFogState& state ){
1131 glFogi( GL_FOG_MODE, state.mode );
1132 glFogf( GL_FOG_DENSITY, state.density );
1133 glFogf( GL_FOG_START, state.start );
1134 glFogf( GL_FOG_END, state.end );
1135 glFogi( GL_FOG_INDEX, state.index );
1136 glFogfv( GL_FOG_COLOR, vector4_to_array( state.colour ) );
1139 #define DEBUG_SHADERS 0
1141 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver
1143 class CreateOpenGLShader
1145 OpenGLShaderCache* m_cache;
1147 explicit CreateOpenGLShader( OpenGLShaderCache* cache = 0 )
1150 OpenGLShader* construct( const CopiedString& name ){
1151 OpenGLShader* shader = new OpenGLShader;
1152 if ( m_cache->realised() ) {
1153 shader->realise( name );
1157 void destroy( OpenGLShader* shader ){
1158 if ( m_cache->realised() ) {
1159 shader->unrealise();
1165 typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1167 std::size_t m_unrealised;
1169 bool m_lightingEnabled;
1170 bool m_lightingSupported;
1171 bool m_useShaderLanguage;
1175 : m_shaders( CreateOpenGLShader( this ) ),
1176 m_unrealised( 3 ), // wait until shaders, gl-context and textures are realised before creating any render-states
1177 m_lightingEnabled( true ),
1178 m_lightingSupported( false ),
1179 m_useShaderLanguage( false ),
1180 m_lightsChanged( true ),
1181 m_traverseRenderablesMutex( false ){
1183 ~OpenGLShaderCache(){
1184 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1186 globalOutputStream() << "leaked shader: " << makeQuoted( ( *i ).key.c_str() ) << "\n";
1189 Shader* capture( const char* name ){
1190 ASSERT_MESSAGE( name[0] == '$'
1194 || strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
1196 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1198 return m_shaders.capture( name ).get();
1200 void release( const char *name ){
1202 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1204 m_shaders.release( name );
1206 void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
1207 glMatrixMode( GL_PROJECTION );
1208 glLoadMatrixf( reinterpret_cast<const float*>( &projection ) );
1210 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1213 glMatrixMode( GL_MODELVIEW );
1214 glLoadMatrixf( reinterpret_cast<const float*>( &modelview ) );
1216 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1219 ASSERT_MESSAGE( realised(), "render states are not realised" );
1221 // global settings that are not set in renderstates
1222 glFrontFace( GL_CW );
1223 glCullFace( GL_BACK );
1224 glPolygonOffset( -1, 1 );
1226 const GLubyte pattern[132] = {
1227 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1228 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
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
1244 glPolygonStipple( pattern );
1246 glEnableClientState( GL_VERTEX_ARRAY );
1247 g_vertexArray_enabled = true;
1248 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1250 if ( GlobalOpenGL().GL_1_3() ) {
1251 glActiveTexture( GL_TEXTURE0 );
1252 glClientActiveTexture( GL_TEXTURE0 );
1255 if ( GlobalOpenGL().ARB_shader_objects() ) {
1256 glUseProgramObjectARB( 0 );
1257 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
1258 glDisableVertexAttribArrayARB( c_attr_Tangent );
1259 glDisableVertexAttribArrayARB( c_attr_Binormal );
1262 if ( globalstate & RENDER_TEXTURE ) {
1263 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1264 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
1267 OpenGLState current;
1268 OpenGLState_constructDefault( current );
1269 current.m_sort = OpenGLState::eSortFirst;
1271 // default renderstate settings
1272 glLineStipple( current.m_linestipple_factor, current.m_linestipple_pattern );
1273 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1274 glDisable( GL_LIGHTING );
1275 glDisable( GL_TEXTURE_2D );
1276 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1277 g_texcoordArray_enabled = false;
1278 glDisableClientState( GL_COLOR_ARRAY );
1279 g_colorArray_enabled = false;
1280 glDisableClientState( GL_NORMAL_ARRAY );
1281 g_normalArray_enabled = false;
1282 glDisable( GL_BLEND );
1283 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1284 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1285 glDisable( GL_CULL_FACE );
1286 glShadeModel( GL_FLAT );
1287 glDisable( GL_DEPTH_TEST );
1288 glDepthMask( GL_FALSE );
1289 glDisable( GL_ALPHA_TEST );
1290 glDisable( GL_LINE_STIPPLE );
1291 glDisable( GL_POLYGON_STIPPLE );
1292 glDisable( GL_POLYGON_OFFSET_LINE );
1294 glBindTexture( GL_TEXTURE_2D, 0 );
1295 glColor4f( 1,1,1,1 );
1296 glDepthFunc( GL_LESS );
1297 glAlphaFunc( GL_ALWAYS, 0 );
1301 glHint( GL_FOG_HINT, GL_NICEST );
1302 glDisable( GL_FOG );
1303 setFogState( OpenGLFogState() );
1305 GlobalOpenGL_debugAssertNoErrors();
1307 debug_string( "begin rendering" );
1308 for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
1310 ( *i ).second->render( current, globalstate, viewer );
1312 debug_string( "end rendering" );
1315 if ( --m_unrealised == 0 ) {
1316 if ( lightingSupported() && lightingEnabled() ) {
1317 if ( useShaderLanguage() ) {
1318 g_bumpGLSL.create();
1319 g_depthFillGLSL.create();
1324 g_depthFillARB.create();
1328 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1330 if ( !( *i ).value.empty() ) {
1331 ( *i ).value->realise( i->key );
1337 if ( ++m_unrealised == 1 ) {
1338 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1340 if ( !( *i ).value.empty() ) {
1341 ( *i ).value->unrealise();
1344 if ( GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled() ) {
1345 if ( useShaderLanguage() ) {
1346 g_bumpGLSL.destroy();
1347 g_depthFillGLSL.destroy();
1351 g_bumpARB.destroy();
1352 g_depthFillARB.destroy();
1358 return m_unrealised == 0;
1362 bool lightingEnabled() const {
1363 return m_lightingEnabled;
1365 bool lightingSupported() const {
1366 return m_lightingSupported;
1368 bool useShaderLanguage() const {
1369 return m_useShaderLanguage;
1371 void setLighting( bool supported, bool enabled ){
1372 bool refresh = ( m_lightingSupported && m_lightingEnabled ) != ( supported && enabled );
1376 GlobalShaderSystem().setLightingEnabled( supported && enabled );
1379 m_lightingSupported = supported;
1380 m_lightingEnabled = enabled;
1386 void extensionsInitialised(){
1387 setLighting( GlobalOpenGL().GL_1_3()
1388 && GlobalOpenGL().ARB_vertex_program()
1389 && GlobalOpenGL().ARB_fragment_program()
1390 && GlobalOpenGL().ARB_shader_objects()
1391 && GlobalOpenGL().ARB_vertex_shader()
1392 && GlobalOpenGL().ARB_fragment_shader()
1393 && GlobalOpenGL().ARB_shading_language_100(),
1397 if ( !lightingSupported() ) {
1398 globalOutputStream() << "Lighting mode requires OpenGL features not supported by your graphics drivers:\n";
1399 if ( !GlobalOpenGL().GL_1_3() ) {
1400 globalOutputStream() << " GL version 1.3 or better\n";
1402 if ( !GlobalOpenGL().ARB_vertex_program() ) {
1403 globalOutputStream() << " GL_ARB_vertex_program\n";
1405 if ( !GlobalOpenGL().ARB_fragment_program() ) {
1406 globalOutputStream() << " GL_ARB_fragment_program\n";
1408 if ( !GlobalOpenGL().ARB_shader_objects() ) {
1409 globalOutputStream() << " GL_ARB_shader_objects\n";
1411 if ( !GlobalOpenGL().ARB_vertex_shader() ) {
1412 globalOutputStream() << " GL_ARB_vertex_shader\n";
1414 if ( !GlobalOpenGL().ARB_fragment_shader() ) {
1415 globalOutputStream() << " GL_ARB_fragment_shader\n";
1417 if ( !GlobalOpenGL().ARB_shading_language_100() ) {
1418 globalOutputStream() << " GL_ARB_shading_language_100\n";
1422 void setLightingEnabled( bool enabled ){
1423 setLighting( m_lightingSupported, enabled );
1428 RendererLights m_lights;
1429 bool m_lightsChanged;
1430 typedef std::map<LightCullable*, LinearLightList> LightLists;
1431 LightLists m_lightLists;
1433 const LightList& attach( LightCullable& cullable ){
1434 return ( *m_lightLists.insert( LightLists::value_type( &cullable, LinearLightList( cullable, m_lights, EvaluateChangedCaller( *this ) ) ) ).first ).second;
1436 void detach( LightCullable& cullable ){
1437 m_lightLists.erase( &cullable );
1439 void changed( LightCullable& cullable ){
1440 LightLists::iterator i = m_lightLists.find( &cullable );
1441 ASSERT_MESSAGE( i != m_lightLists.end(), "cullable not attached" );
1442 ( *i ).second.lightsChanged();
1444 void attach( RendererLight& light ){
1445 ASSERT_MESSAGE( m_lights.find( &light ) == m_lights.end(), "light could not be attached" );
1446 m_lights.insert( &light );
1449 void detach( RendererLight& light ){
1450 ASSERT_MESSAGE( m_lights.find( &light ) != m_lights.end(), "light could not be detached" );
1451 m_lights.erase( &light );
1454 void changed( RendererLight& light ){
1455 m_lightsChanged = true;
1457 void evaluateChanged(){
1458 if ( m_lightsChanged ) {
1459 m_lightsChanged = false;
1460 for ( LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i )
1462 ( *i ).second.lightsChanged();
1466 typedef MemberCaller<OpenGLShaderCache, &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1468 typedef std::set<const Renderable*> Renderables;
1469 Renderables m_renderables;
1470 mutable bool m_traverseRenderablesMutex;
1473 void attachRenderable( const Renderable& renderable ){
1474 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "attaching renderable during traversal" );
1475 ASSERT_MESSAGE( m_renderables.find( &renderable ) == m_renderables.end(), "renderable could not be attached" );
1476 m_renderables.insert( &renderable );
1478 void detachRenderable( const Renderable& renderable ){
1479 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "detaching renderable during traversal" );
1480 ASSERT_MESSAGE( m_renderables.find( &renderable ) != m_renderables.end(), "renderable could not be detached" );
1481 m_renderables.erase( &renderable );
1483 void forEachRenderable( const RenderableCallback& callback ) const {
1484 ASSERT_MESSAGE( !m_traverseRenderablesMutex, "for-each during traversal" );
1485 m_traverseRenderablesMutex = true;
1486 for ( Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i )
1488 callback( *( *i ) );
1490 m_traverseRenderablesMutex = false;
1494 static OpenGLShaderCache* g_ShaderCache;
1496 void ShaderCache_extensionsInitialised(){
1497 g_ShaderCache->extensionsInitialised();
1500 void ShaderCache_setBumpEnabled( bool enabled ){
1501 g_ShaderCache->setLightingEnabled( enabled );
1505 Vector3 g_DebugShaderColours[256];
1506 Shader* g_defaultPointLight = 0;
1508 void ShaderCache_Construct(){
1509 g_ShaderCache = new OpenGLShaderCache;
1510 GlobalTexturesCache().attach( *g_ShaderCache );
1511 GlobalShaderSystem().attach( *g_ShaderCache );
1513 if ( g_pGameDescription->mGameType == "doom3" ) {
1514 g_defaultPointLight = g_ShaderCache->capture( "lights/defaultPointLight" );
1515 //Shader* overbright =
1516 g_ShaderCache->capture( "$OVERBRIGHT" );
1518 #if LIGHT_SHADER_DEBUG
1519 for ( std::size_t i = 0; i < 256; ++i )
1521 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1524 g_DebugShaderColours[0] = Vector3( 1, 0, 0 );
1525 g_DebugShaderColours[1] = Vector3( 1, 0.5, 0 );
1526 g_DebugShaderColours[2] = Vector3( 1, 1, 0 );
1527 g_DebugShaderColours[3] = Vector3( 0.5, 1, 0 );
1528 g_DebugShaderColours[4] = Vector3( 0, 1, 0 );
1529 g_DebugShaderColours[5] = Vector3( 0, 1, 0.5 );
1530 g_DebugShaderColours[6] = Vector3( 0, 1, 1 );
1531 g_DebugShaderColours[7] = Vector3( 0, 0.5, 1 );
1532 g_DebugShaderColours[8] = Vector3( 0, 0, 1 );
1533 g_DebugShaderColours[9] = Vector3( 0.5, 0, 1 );
1534 g_DebugShaderColours[10] = Vector3( 1, 0, 1 );
1535 g_DebugShaderColours[11] = Vector3( 1, 0, 0.5 );
1537 g_lightDebugShaders.reserve( 256 );
1538 StringOutputStream buffer( 256 );
1539 for ( std::size_t i = 0; i < 256; ++i )
1541 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1542 g_lightDebugShaders.push_back( g_ShaderCache->capture( buffer.c_str() ) );
1549 void ShaderCache_Destroy(){
1550 if ( g_pGameDescription->mGameType == "doom3" ) {
1551 g_ShaderCache->release( "lights/defaultPointLight" );
1552 g_ShaderCache->release( "$OVERBRIGHT" );
1553 g_defaultPointLight = 0;
1555 #if LIGHT_SHADER_DEBUG
1556 g_lightDebugShaders.clear();
1557 StringOutputStream buffer( 256 );
1558 for ( std::size_t i = 0; i < 256; ++i )
1560 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1561 g_ShaderCache->release( buffer.c_str() );
1566 GlobalShaderSystem().detach( *g_ShaderCache );
1567 GlobalTexturesCache().detach( *g_ShaderCache );
1568 delete g_ShaderCache;
1571 ShaderCache* GetShaderCache(){
1572 return g_ShaderCache;
1575 inline void setTextureState( GLint& current, const GLint& texture, GLenum textureUnit ){
1576 if ( texture != current ) {
1577 glActiveTexture( textureUnit );
1578 glClientActiveTexture( textureUnit );
1579 glBindTexture( GL_TEXTURE_2D, texture );
1580 GlobalOpenGL_debugAssertNoErrors();
1585 inline void setTextureState( GLint& current, const GLint& texture ){
1586 if ( texture != current ) {
1587 glBindTexture( GL_TEXTURE_2D, texture );
1588 GlobalOpenGL_debugAssertNoErrors();
1593 inline void setState( unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag ){
1594 if ( delta & state & flag ) {
1596 GlobalOpenGL_debugAssertNoErrors();
1598 else if ( delta & ~state & flag ) {
1599 glDisable( glflag );
1600 GlobalOpenGL_debugAssertNoErrors();
1604 void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
1605 debug_int( "sort", int(self.m_sort) );
1606 debug_int( "texture", self.m_texture );
1607 debug_int( "state", self.m_state );
1608 debug_int( "address", int(std::size_t( &self ) ) );
1612 if ( self.m_state & RENDER_OVERRIDE ) {
1613 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1616 const unsigned int state = self.m_state & globalstate;
1617 const unsigned int delta = state ^ current.m_state;
1619 GlobalOpenGL_debugAssertNoErrors();
1621 GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0;
1623 if ( program != current.m_program ) {
1624 if ( current.m_program != 0 ) {
1625 current.m_program->disable();
1626 glColor4fv( vector4_to_array( current.m_colour ) );
1627 debug_colour( "cleaning program" );
1630 current.m_program = program;
1632 if ( current.m_program != 0 ) {
1633 current.m_program->enable();
1637 if ( delta & state & RENDER_FILL ) {
1638 //qglPolygonMode (GL_BACK, GL_LINE);
1639 //qglPolygonMode (GL_FRONT, GL_FILL);
1640 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1641 GlobalOpenGL_debugAssertNoErrors();
1643 else if ( delta & ~state & RENDER_FILL ) {
1644 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1645 GlobalOpenGL_debugAssertNoErrors();
1648 setState( state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE );
1650 if ( delta & state & RENDER_LIGHTING ) {
1651 glEnable( GL_LIGHTING );
1652 glEnable( GL_COLOR_MATERIAL );
1653 glEnable( GL_RESCALE_NORMAL );
1654 glEnableClientState( GL_NORMAL_ARRAY );
1655 GlobalOpenGL_debugAssertNoErrors();
1656 g_normalArray_enabled = true;
1658 else if ( delta & ~state & RENDER_LIGHTING ) {
1659 glDisable( GL_LIGHTING );
1660 glDisable( GL_COLOR_MATERIAL );
1661 glDisable( GL_RESCALE_NORMAL );
1662 glDisableClientState( GL_NORMAL_ARRAY );
1663 GlobalOpenGL_debugAssertNoErrors();
1664 g_normalArray_enabled = false;
1667 if ( delta & state & RENDER_TEXTURE ) {
1668 GlobalOpenGL_debugAssertNoErrors();
1670 if ( GlobalOpenGL().GL_1_3() ) {
1671 glActiveTexture( GL_TEXTURE0 );
1672 glClientActiveTexture( GL_TEXTURE0 );
1675 glEnable( GL_TEXTURE_2D );
1677 glColor4f( 1,1,1,self.m_colour[3] );
1678 debug_colour( "setting texture" );
1680 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1681 GlobalOpenGL_debugAssertNoErrors();
1682 g_texcoordArray_enabled = true;
1684 else if ( delta & ~state & RENDER_TEXTURE ) {
1685 if ( GlobalOpenGL().GL_1_3() ) {
1686 glActiveTexture( GL_TEXTURE0 );
1687 glClientActiveTexture( GL_TEXTURE0 );
1690 glDisable( GL_TEXTURE_2D );
1691 glBindTexture( GL_TEXTURE_2D, 0 );
1692 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1694 GlobalOpenGL_debugAssertNoErrors();
1695 g_texcoordArray_enabled = false;
1698 if ( delta & state & RENDER_BLEND ) {
1699 // FIXME: some .TGA are buggy, have a completely empty alpha channel
1700 // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1701 // so I decided using GL_DECAL instead
1702 // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1703 // this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1705 glEnable( GL_BLEND );
1706 if ( GlobalOpenGL().GL_1_3() ) {
1707 glActiveTexture( GL_TEXTURE0 );
1709 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
1710 GlobalOpenGL_debugAssertNoErrors();
1712 else if ( delta & ~state & RENDER_BLEND ) {
1713 glDisable( GL_BLEND );
1714 if ( GlobalOpenGL().GL_1_3() ) {
1715 glActiveTexture( GL_TEXTURE0 );
1717 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1718 GlobalOpenGL_debugAssertNoErrors();
1721 setState( state, delta, RENDER_CULLFACE, GL_CULL_FACE );
1723 if ( delta & state & RENDER_SMOOTH ) {
1724 glShadeModel( GL_SMOOTH );
1725 GlobalOpenGL_debugAssertNoErrors();
1727 else if ( delta & ~state & RENDER_SMOOTH ) {
1728 glShadeModel( GL_FLAT );
1729 GlobalOpenGL_debugAssertNoErrors();
1732 setState( state, delta, RENDER_SCALED, GL_NORMALIZE ); // not GL_RESCALE_NORMAL
1734 setState( state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST );
1736 if ( delta & state & RENDER_DEPTHWRITE ) {
1737 glDepthMask( GL_TRUE );
1740 GLboolean depthEnabled;
1741 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1742 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1744 debug_string( "enabled depth-buffer writing" );
1746 GlobalOpenGL_debugAssertNoErrors();
1748 else if ( delta & ~state & RENDER_DEPTHWRITE ) {
1749 glDepthMask( GL_FALSE );
1752 GLboolean depthEnabled;
1753 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1754 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1756 debug_string( "disabled depth-buffer writing" );
1758 GlobalOpenGL_debugAssertNoErrors();
1761 if ( delta & state & RENDER_COLOURWRITE ) {
1762 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
1763 GlobalOpenGL_debugAssertNoErrors();
1765 else if ( delta & ~state & RENDER_COLOURWRITE ) {
1766 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
1767 GlobalOpenGL_debugAssertNoErrors();
1770 setState( state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST );
1772 if ( delta & state & RENDER_COLOURARRAY ) {
1773 glEnableClientState( GL_COLOR_ARRAY );
1774 GlobalOpenGL_debugAssertNoErrors();
1775 debug_colour( "enabling color_array" );
1776 g_colorArray_enabled = true;
1778 else if ( delta & ~state & RENDER_COLOURARRAY ) {
1779 glDisableClientState( GL_COLOR_ARRAY );
1780 glColor4fv( vector4_to_array( self.m_colour ) );
1781 debug_colour( "cleaning color_array" );
1782 GlobalOpenGL_debugAssertNoErrors();
1783 g_colorArray_enabled = false;
1786 if ( delta & ~state & RENDER_COLOURCHANGE ) {
1787 glColor4fv( vector4_to_array( self.m_colour ) );
1788 GlobalOpenGL_debugAssertNoErrors();
1791 setState( state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE );
1792 setState( state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH );
1794 setState( state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE );
1795 setState( state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH );
1797 setState( state, delta, RENDER_FOG, GL_FOG );
1799 if ( ( state & RENDER_FOG ) != 0 ) {
1800 setFogState( self.m_fog );
1801 GlobalOpenGL_debugAssertNoErrors();
1802 current.m_fog = self.m_fog;
1805 if ( state & RENDER_DEPTHTEST && self.m_depthfunc != current.m_depthfunc ) {
1806 glDepthFunc( self.m_depthfunc );
1807 GlobalOpenGL_debugAssertNoErrors();
1808 current.m_depthfunc = self.m_depthfunc;
1811 if ( state & RENDER_LINESTIPPLE
1812 && ( self.m_linestipple_factor != current.m_linestipple_factor
1813 || self.m_linestipple_pattern != current.m_linestipple_pattern ) ) {
1814 glLineStipple( self.m_linestipple_factor, self.m_linestipple_pattern );
1815 GlobalOpenGL_debugAssertNoErrors();
1816 current.m_linestipple_factor = self.m_linestipple_factor;
1817 current.m_linestipple_pattern = self.m_linestipple_pattern;
1821 if ( state & RENDER_ALPHATEST
1822 && ( self.m_alphafunc != current.m_alphafunc
1823 || self.m_alpharef != current.m_alpharef ) ) {
1824 glAlphaFunc( self.m_alphafunc, self.m_alpharef );
1825 GlobalOpenGL_debugAssertNoErrors();
1826 current.m_alphafunc = self.m_alphafunc;
1827 current.m_alpharef = self.m_alpharef;
1839 //if(state & RENDER_TEXTURE) != 0)
1841 texture0 = self.m_texture;
1842 texture1 = self.m_texture1;
1843 texture2 = self.m_texture2;
1844 texture3 = self.m_texture3;
1845 texture4 = self.m_texture4;
1846 texture5 = self.m_texture5;
1847 texture6 = self.m_texture6;
1848 texture7 = self.m_texture7;
1851 if ( GlobalOpenGL().GL_1_3() ) {
1852 setTextureState( current.m_texture, texture0, GL_TEXTURE0 );
1853 setTextureState( current.m_texture1, texture1, GL_TEXTURE1 );
1854 setTextureState( current.m_texture2, texture2, GL_TEXTURE2 );
1855 setTextureState( current.m_texture3, texture3, GL_TEXTURE3 );
1856 setTextureState( current.m_texture4, texture4, GL_TEXTURE4 );
1857 setTextureState( current.m_texture5, texture5, GL_TEXTURE5 );
1858 setTextureState( current.m_texture6, texture6, GL_TEXTURE6 );
1859 setTextureState( current.m_texture7, texture7, GL_TEXTURE7 );
1863 setTextureState( current.m_texture, texture0 );
1868 if ( state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3] ) {
1869 debug_colour( "setting alpha" );
1870 glColor4f( 1,1,1,self.m_colour[3] );
1871 GlobalOpenGL_debugAssertNoErrors();
1874 if ( !( state & RENDER_TEXTURE )
1875 && ( self.m_colour[0] != current.m_colour[0]
1876 || self.m_colour[1] != current.m_colour[1]
1877 || self.m_colour[2] != current.m_colour[2]
1878 || self.m_colour[3] != current.m_colour[3] ) ) {
1879 glColor4fv( vector4_to_array( self.m_colour ) );
1880 debug_colour( "setting non-texture" );
1881 GlobalOpenGL_debugAssertNoErrors();
1883 current.m_colour = self.m_colour;
1885 if ( state & RENDER_BLEND
1886 && ( self.m_blend_src != current.m_blend_src || self.m_blend_dst != current.m_blend_dst ) ) {
1887 glBlendFunc( self.m_blend_src, self.m_blend_dst );
1888 GlobalOpenGL_debugAssertNoErrors();
1889 current.m_blend_src = self.m_blend_src;
1890 current.m_blend_dst = self.m_blend_dst;
1893 if ( !( state & RENDER_FILL )
1894 && self.m_linewidth != current.m_linewidth ) {
1895 glLineWidth( self.m_linewidth );
1896 GlobalOpenGL_debugAssertNoErrors();
1897 current.m_linewidth = self.m_linewidth;
1900 if ( !( state & RENDER_FILL )
1901 && self.m_pointsize != current.m_pointsize ) {
1902 glPointSize( self.m_pointsize );
1903 GlobalOpenGL_debugAssertNoErrors();
1904 current.m_pointsize = self.m_pointsize;
1907 current.m_state = state;
1909 GlobalOpenGL_debugAssertNoErrors();
1912 void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1913 const Matrix4* transform = 0;
1915 for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
1917 //qglLoadMatrixf(i->m_transform);
1918 if ( !transform || ( transform != ( *i ).m_transform && !matrix4_affine_equal( *transform, *( *i ).m_transform ) ) ) {
1920 transform = ( *i ).m_transform;
1923 glMultMatrixf( reinterpret_cast<const float*>( transform ) );
1924 glFrontFace( ( ( current.m_state & RENDER_CULLFACE ) != 0 && matrix4_handedness( *transform ) == MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW );
1929 if ( current.m_program != 0 && ( *i ).m_light != 0 ) {
1930 const IShader& lightShader = static_cast<OpenGLShader*>( ( *i ).m_light->getShader() )->getShader();
1931 if ( lightShader.firstLayer() != 0 ) {
1932 GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
1933 GLuint attenuation_z = lightShader.lightFalloffImage() != 0
1934 ? lightShader.lightFalloffImage()->texture_number
1935 : static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
1937 setTextureState( current.m_texture3, attenuation_xy, GL_TEXTURE3 );
1938 glActiveTexture( GL_TEXTURE3 );
1939 glBindTexture( GL_TEXTURE_2D, attenuation_xy );
1940 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1941 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
1943 setTextureState( current.m_texture4, attenuation_z, GL_TEXTURE4 );
1944 glActiveTexture( GL_TEXTURE4 );
1945 glBindTexture( GL_TEXTURE_2D, attenuation_z );
1946 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
1947 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1950 AABB lightBounds( ( *i ).m_light->aabb() );
1952 Matrix4 world2light( g_matrix4_identity );
1954 if ( ( *i ).m_light->isProjected() ) {
1955 world2light = ( *i ).m_light->projection();
1956 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
1957 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
1959 if ( !( *i ).m_light->isProjected() ) {
1960 matrix4_translate_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
1961 matrix4_scale_by_vec3( world2light, Vector3( 0.5f, 0.5f, 0.5f ) );
1962 matrix4_scale_by_vec3( world2light, Vector3( 1.0f / lightBounds.extents.x(), 1.0f / lightBounds.extents.y(), 1.0f / lightBounds.extents.z() ) );
1963 matrix4_multiply_by_matrix4( world2light, matrix4_transposed( ( *i ).m_light->rotation() ) );
1964 matrix4_translate_by_vec3( world2light, vector3_negated( lightBounds.origin ) ); // world->lightBounds
1967 current.m_program->setParameters( viewer, *( *i ).m_transform, lightBounds.origin + ( *i ).m_light->offset(), ( *i ).m_light->colour(), world2light );
1968 debug_string( "set lightBounds parameters" );
1972 ( *i ).m_renderable->render( current.m_state );
1975 renderables.clear();
1978 void OpenGLStateBucket::render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1979 if ( ( globalstate & m_state.m_state & RENDER_SCREEN ) != 0 ) {
1980 OpenGLState_apply( m_state, current, globalstate );
1981 debug_colour( "screen fill" );
1983 glMatrixMode( GL_PROJECTION );
1985 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1987 glMatrixMode( GL_MODELVIEW );
1989 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1991 glBegin( GL_QUADS );
1992 glVertex3f( -1, -1, 0 );
1993 glVertex3f( 1, -1, 0 );
1994 glVertex3f( 1, 1, 0 );
1995 glVertex3f( -1, 1, 0 );
1998 glMatrixMode( GL_PROJECTION );
2001 glMatrixMode( GL_MODELVIEW );
2004 else if ( !m_renderables.empty() ) {
2005 OpenGLState_apply( m_state, current, globalstate );
2006 Renderables_flush( m_renderables, current, globalstate, viewer );
2011 class OpenGLStateMap : public OpenGLStateLibrary
2013 typedef std::map<CopiedString, OpenGLState> States;
2017 ASSERT_MESSAGE( m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty" );
2020 typedef States::iterator iterator;
2022 return m_states.begin();
2025 return m_states.end();
2028 void getDefaultState( OpenGLState& state ) const {
2029 OpenGLState_constructDefault( state );
2032 void insert( const char* name, const OpenGLState& state ){
2033 bool inserted = m_states.insert( States::value_type( name, state ) ).second;
2034 ASSERT_MESSAGE( inserted, "OpenGLStateMap::insert: " << name << " already exists" );
2036 void erase( const char* name ){
2037 std::size_t count = m_states.erase( name );
2038 ASSERT_MESSAGE( count == 1, "OpenGLStateMap::erase: " << name << " does not exist" );
2041 iterator find( const char* name ){
2042 return m_states.find( name );
2046 OpenGLStateMap* g_openglStates = 0;
2048 inline GLenum convertBlendFactor( BlendFactor factor ){
2055 case BLEND_SRC_COLOUR:
2056 return GL_SRC_COLOR;
2057 case BLEND_ONE_MINUS_SRC_COLOUR:
2058 return GL_ONE_MINUS_SRC_COLOR;
2059 case BLEND_SRC_ALPHA:
2060 return GL_SRC_ALPHA;
2061 case BLEND_ONE_MINUS_SRC_ALPHA:
2062 return GL_ONE_MINUS_SRC_ALPHA;
2063 case BLEND_DST_COLOUR:
2064 return GL_DST_COLOR;
2065 case BLEND_ONE_MINUS_DST_COLOUR:
2066 return GL_ONE_MINUS_DST_COLOR;
2067 case BLEND_DST_ALPHA:
2068 return GL_DST_ALPHA;
2069 case BLEND_ONE_MINUS_DST_ALPHA:
2070 return GL_ONE_MINUS_DST_ALPHA;
2071 case BLEND_SRC_ALPHA_SATURATE:
2072 return GL_SRC_ALPHA_SATURATE;
2077 /// \todo Define special-case shaders in a data file.
2078 void OpenGLShader::construct( const char* name ){
2079 OpenGLState& state = appendDefaultPass();
2083 sscanf( name, "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2084 state.m_colour[3] = 1.0f;
2085 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2086 state.m_sort = OpenGLState::eSortFullbright;
2090 sscanf( name, "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2091 state.m_colour[3] = 0.5f;
2092 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_BLEND;
2093 state.m_sort = OpenGLState::eSortTranslucent;
2097 sscanf( name, "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2] );
2098 state.m_colour[3] = 1;
2099 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2100 state.m_sort = OpenGLState::eSortFullbright;
2101 state.m_depthfunc = GL_LESS;
2102 state.m_linewidth = 1;
2103 state.m_pointsize = 1;
2108 OpenGLStateMap::iterator i = g_openglStates->find( name );
2109 if ( i != g_openglStates->end() ) {
2110 state = ( *i ).second;
2114 if ( string_equal( name + 1, "POINT" ) ) {
2115 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2116 state.m_sort = OpenGLState::eSortControlFirst;
2117 state.m_pointsize = 4;
2119 else if ( string_equal( name + 1, "SELPOINT" ) ) {
2120 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2121 state.m_sort = OpenGLState::eSortControlFirst + 1;
2122 state.m_pointsize = 4;
2124 else if ( string_equal( name + 1, "BIGPOINT" ) ) {
2125 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2126 state.m_sort = OpenGLState::eSortControlFirst;
2127 state.m_pointsize = 6;
2129 else if ( string_equal( name + 1, "PIVOT" ) ) {
2130 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
2131 state.m_sort = OpenGLState::eSortGUI1;
2132 state.m_linewidth = 2;
2133 state.m_depthfunc = GL_LEQUAL;
2135 OpenGLState& hiddenLine = appendDefaultPass();
2136 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
2137 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2138 hiddenLine.m_linewidth = 2;
2139 hiddenLine.m_depthfunc = GL_GREATER;
2141 else if ( string_equal( name + 1, "LATTICE" ) ) {
2142 state.m_colour[0] = 1;
2143 state.m_colour[1] = 0.5;
2144 state.m_colour[2] = 0;
2145 state.m_colour[3] = 1;
2146 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2147 state.m_sort = OpenGLState::eSortControlFirst;
2149 else if ( string_equal( name + 1, "WIREFRAME" ) ) {
2150 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2151 state.m_sort = OpenGLState::eSortFullbright;
2153 else if ( string_equal( name + 1, "CAM_HIGHLIGHT" ) ) {
2154 state.m_colour[0] = 1;
2155 state.m_colour[1] = 0;
2156 state.m_colour[2] = 0;
2157 state.m_colour[3] = 0.3f;
2158 state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2159 state.m_sort = OpenGLState::eSortHighlight;
2160 state.m_depthfunc = GL_LEQUAL;
2162 else if ( string_equal( name + 1, "CAM_OVERLAY" ) ) {
2164 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2165 state.m_sort = OpenGLState::eSortOverlayFirst;
2167 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2168 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2169 state.m_depthfunc = GL_LEQUAL;
2171 OpenGLState& hiddenLine = appendDefaultPass();
2172 hiddenLine.m_colour[0] = 0.75;
2173 hiddenLine.m_colour[1] = 0.75;
2174 hiddenLine.m_colour[2] = 0.75;
2175 hiddenLine.m_colour[3] = 1;
2176 hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE | RENDER_LINESTIPPLE;
2177 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2178 hiddenLine.m_depthfunc = GL_GREATER;
2179 hiddenLine.m_linestipple_factor = 2;
2182 else if ( string_equal( name + 1, "XY_OVERLAY" ) ) {
2183 state.m_colour[0] = g_xywindow_globals.color_selbrushes[0];
2184 state.m_colour[1] = g_xywindow_globals.color_selbrushes[1];
2185 state.m_colour[2] = g_xywindow_globals.color_selbrushes[2];
2186 state.m_colour[3] = 1;
2187 state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
2188 state.m_sort = OpenGLState::eSortOverlayFirst;
2189 state.m_linewidth = 2;
2190 state.m_linestipple_factor = 3;
2192 else if ( string_equal( name + 1, "DEBUG_CLIPPED" ) ) {
2193 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2194 state.m_sort = OpenGLState::eSortLast;
2196 else if ( string_equal( name + 1, "POINTFILE" ) ) {
2197 state.m_colour[0] = 1;
2198 state.m_colour[1] = 0;
2199 state.m_colour[2] = 0;
2200 state.m_colour[3] = 1;
2201 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2202 state.m_sort = OpenGLState::eSortFullbright;
2203 state.m_linewidth = 4;
2205 else if ( string_equal( name + 1, "LIGHT_SPHERE" ) ) {
2206 state.m_colour[0] = .15f * .95f;
2207 state.m_colour[1] = .15f * .95f;
2208 state.m_colour[2] = .15f * .95f;
2209 state.m_colour[3] = 1;
2210 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2211 state.m_blend_src = GL_ONE;
2212 state.m_blend_dst = GL_ONE;
2213 state.m_sort = OpenGLState::eSortTranslucent;
2215 else if ( string_equal( name + 1, "Q3MAP2_LIGHT_SPHERE" ) ) {
2216 state.m_colour[0] = .05f;
2217 state.m_colour[1] = .05f;
2218 state.m_colour[2] = .05f;
2219 state.m_colour[3] = 1;
2220 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
2221 state.m_blend_src = GL_ONE;
2222 state.m_blend_dst = GL_ONE;
2223 state.m_sort = OpenGLState::eSortTranslucent;
2225 else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
2227 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2228 state.m_sort = OpenGLState::eSortOverlayFirst;
2230 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2231 state.m_sort = OpenGLState::eSortGUI1;
2232 state.m_depthfunc = GL_LEQUAL;
2234 OpenGLState& hiddenLine = appendDefaultPass();
2235 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE | RENDER_LINESTIPPLE;
2236 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2237 hiddenLine.m_depthfunc = GL_GREATER;
2240 else if ( string_equal( name + 1, "FLATSHADE_OVERLAY" ) ) {
2241 state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY | RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2242 state.m_sort = OpenGLState::eSortGUI1;
2243 state.m_depthfunc = GL_LEQUAL;
2245 OpenGLState& hiddenLine = appendDefaultPass();
2246 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;
2247 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2248 hiddenLine.m_depthfunc = GL_GREATER;
2250 else if ( string_equal( name + 1, "CLIPPER_OVERLAY" ) ) {
2251 state.m_colour[0] = g_xywindow_globals.color_clipper[0];
2252 state.m_colour[1] = g_xywindow_globals.color_clipper[1];
2253 state.m_colour[2] = g_xywindow_globals.color_clipper[2];
2254 state.m_colour[3] = 1;
2255 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE;
2256 state.m_sort = OpenGLState::eSortOverlayFirst;
2258 else if ( string_equal( name + 1, "OVERBRIGHT" ) ) {
2259 const float lightScale = 2;
2260 state.m_colour[0] = lightScale * 0.5f;
2261 state.m_colour[1] = lightScale * 0.5f;
2262 state.m_colour[2] = lightScale * 0.5f;
2263 state.m_colour[3] = 0.5;
2264 state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN;
2265 state.m_sort = OpenGLState::eSortOverbrighten;
2266 state.m_blend_src = GL_DST_COLOR;
2267 state.m_blend_dst = GL_SRC_COLOR;
2271 // default to something recognisable.. =)
2272 ERROR_MESSAGE( "hardcoded renderstate not found" );
2273 state.m_colour[0] = 1;
2274 state.m_colour[1] = 0;
2275 state.m_colour[2] = 1;
2276 state.m_colour[3] = 1;
2277 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2278 state.m_sort = OpenGLState::eSortFirst;
2282 // construction from IShader
2283 m_shader = QERApp_Shader_ForName( name );
2285 if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && m_shader->getBump()->texture_number != 0 ) { // is a bump shader
2286 state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM;
2287 state.m_colour[0] = 0;
2288 state.m_colour[1] = 0;
2289 state.m_colour[2] = 0;
2290 state.m_colour[3] = 1;
2291 state.m_sort = OpenGLState::eSortOpaque;
2293 if ( g_ShaderCache->useShaderLanguage() ) {
2294 state.m_program = &g_depthFillGLSL;
2298 state.m_program = &g_depthFillARB;
2301 OpenGLState& bumpPass = appendDefaultPass();
2302 bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
2303 bumpPass.m_texture1 = m_shader->getBump()->texture_number;
2304 bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
2306 bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2308 if ( g_ShaderCache->useShaderLanguage() ) {
2309 bumpPass.m_state |= RENDER_LIGHTING;
2310 bumpPass.m_program = &g_bumpGLSL;
2314 bumpPass.m_program = &g_bumpARB;
2317 bumpPass.m_depthfunc = GL_LEQUAL;
2318 bumpPass.m_sort = OpenGLState::eSortMultiFirst;
2319 bumpPass.m_blend_src = GL_ONE;
2320 bumpPass.m_blend_dst = GL_ONE;
2324 state.m_texture = m_shader->getTexture()->texture_number;
2326 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH;
2327 if ( ( m_shader->getFlags() & QER_CULL ) != 0 ) {
2328 if ( m_shader->getCull() == IShader::eCullBack ) {
2329 state.m_state |= RENDER_CULLFACE;
2334 state.m_state |= RENDER_CULLFACE;
2336 if ( ( m_shader->getFlags() & QER_ALPHATEST ) != 0 ) {
2337 state.m_state |= RENDER_ALPHATEST;
2338 IShader::EAlphaFunc alphafunc;
2339 m_shader->getAlphaFunc( &alphafunc, &state.m_alpharef );
2340 switch ( alphafunc )
2342 case IShader::eAlways:
2343 state.m_alphafunc = GL_ALWAYS;
2344 case IShader::eEqual:
2345 state.m_alphafunc = GL_EQUAL;
2346 case IShader::eLess:
2347 state.m_alphafunc = GL_LESS;
2348 case IShader::eGreater:
2349 state.m_alphafunc = GL_GREATER;
2350 case IShader::eLEqual:
2351 state.m_alphafunc = GL_LEQUAL;
2352 case IShader::eGEqual:
2353 state.m_alphafunc = GL_GEQUAL;
2356 reinterpret_cast<Vector3&>( state.m_colour ) = m_shader->getTexture()->color;
2357 state.m_colour[3] = 1.0f;
2359 if ( ( m_shader->getFlags() & QER_TRANS ) != 0 ) {
2360 state.m_state |= RENDER_BLEND;
2361 state.m_colour[3] = m_shader->getTrans();
2362 state.m_sort = OpenGLState::eSortTranslucent;
2363 BlendFunc blendFunc = m_shader->getBlendFunc();
2364 state.m_blend_src = convertBlendFactor( blendFunc.m_src );
2365 state.m_blend_dst = convertBlendFactor( blendFunc.m_dst );
2366 if ( state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA ) {
2367 state.m_state |= RENDER_DEPTHWRITE;
2372 state.m_state |= RENDER_DEPTHWRITE;
2373 state.m_sort = OpenGLState::eSortFullbright;
2380 #include "modulesystem/singletonmodule.h"
2381 #include "modulesystem/moduleregistry.h"
2383 class OpenGLStateLibraryAPI
2385 OpenGLStateMap m_stateMap;
2387 typedef OpenGLStateLibrary Type;
2388 STRING_CONSTANT( Name, "*" );
2390 OpenGLStateLibraryAPI(){
2391 g_openglStates = &m_stateMap;
2393 ~OpenGLStateLibraryAPI(){
2396 OpenGLStateLibrary* getTable(){
2401 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2402 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2403 StaticRegisterModule staticRegisterOpenGLStateLibrary( StaticOpenGLStateLibraryModule::instance() );
2405 class ShaderCacheDependencies : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef
2408 ShaderCacheDependencies() :
2409 GlobalShadersModuleRef( GlobalRadiant().getRequiredGameDescriptionKeyValue( "shaders" ) ){
2413 class ShaderCacheAPI
2415 ShaderCache* m_shaderCache;
2417 typedef ShaderCache Type;
2418 STRING_CONSTANT( Name, "*" );
2421 ShaderCache_Construct();
2423 m_shaderCache = GetShaderCache();
2426 ShaderCache_Destroy();
2428 ShaderCache* getTable(){
2429 return m_shaderCache;
2433 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2434 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2435 StaticRegisterModule staticRegisterShaderCache( StaticShaderCacheModule::instance() );