2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "renderstate.h"
24 #include "debugging/debugging.h"
29 #include "itextures.h"
31 #include "iglrender.h"
32 #include "renderable.h"
33 #include "qerplugin.h"
40 #include "math/matrix.h"
41 #include "math/aabb.h"
42 #include "generic/callback.h"
43 #include "texturelib.h"
44 #include "string/string.h"
45 #include "container/hashfunc.h"
46 #include "container/cache.h"
47 #include "generic/reference.h"
48 #include "moduleobservers.h"
49 #include "stream/filestream.h"
50 #include "stream/stringstream.h"
52 #include "preferences.h"
57 #define DEBUG_RENDER 0
59 inline void debug_string(const char *string)
62 globalOutputStream() << string << "\n";
66 inline void debug_int(const char *comment, int i)
69 globalOutputStream() << comment << " " << i << "\n";
73 inline void debug_colour(const char *comment)
77 glGetFloatv( GL_CURRENT_COLOR, reinterpret_cast<float*>( &v ) );
78 globalOutputStream() << comment << " colour: "
83 if ( glIsEnabled( GL_COLOR_ARRAY ) ) {
84 globalOutputStream() << " ARRAY";
86 if ( glIsEnabled( GL_COLOR_MATERIAL ) ) {
87 globalOutputStream() << " MATERIAL";
89 globalOutputStream() << "\n";
95 StringOutputStream g_renderer_stats;
96 std::size_t g_count_prims;
97 std::size_t g_count_states;
98 std::size_t g_count_transforms;
101 inline void count_prim()
106 inline void count_state()
111 inline void count_transform()
113 ++g_count_transforms;
116 void Renderer_ResetStats()
120 g_count_transforms = 0;
124 const char *Renderer_GetStats()
126 g_renderer_stats.clear();
127 g_renderer_stats << "prims: " << Unsigned(g_count_prims)
128 << " | states: " << Unsigned(g_count_states)
129 << " | transforms: " << Unsigned(g_count_transforms)
130 << " | msec: " << g_timer.elapsed_msec();
131 return g_renderer_stats.c_str();
135 void printShaderLog(GLhandleARB object)
137 GLint log_length = 0;
138 glGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length);
140 Array<char> log(log_length);
141 glGetInfoLogARB(object, log_length, &log_length, log.data());
143 globalErrorStream() << StringRange(log.begin(), log.begin() + log_length) << "\n";
146 void createShader(GLhandleARB program, const char *filename, GLenum type)
148 GLhandleARB shader = glCreateShaderObjectARB(type);
149 GlobalOpenGL_debugAssertNoErrors();
153 std::size_t size = file_size(filename);
154 FileInputStream file(filename);
155 ASSERT_MESSAGE(!file.failed(), "failed to open " << makeQuoted(filename));
156 Array<GLcharARB> buffer(size);
157 size = file.read(reinterpret_cast<StreamBase::byte_type *>( buffer.data()), size);
159 const GLcharARB *string = buffer.data();
160 GLint length = GLint(size);
161 glShaderSourceARB(shader, 1, &string, &length);
166 glCompileShaderARB(shader);
169 glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
172 printShaderLog(shader);
175 ASSERT_MESSAGE(compiled, "shader compile failed: " << makeQuoted(filename));
179 glAttachObjectARB(program, shader);
181 glDeleteObjectARB(shader);
183 GlobalOpenGL_debugAssertNoErrors();
186 void GLSLProgram_link(GLhandleARB program)
188 glLinkProgramARB(program);
190 GLint linked = false;
191 glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked);
194 printShaderLog(program);
197 ASSERT_MESSAGE(linked, "program link failed");
200 void GLSLProgram_validate(GLhandleARB program)
202 glValidateProgramARB(program);
204 GLint validated = false;
205 glGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated);
208 printShaderLog(program);
211 ASSERT_MESSAGE(validated, "program validation failed");
214 bool g_bumpGLSLPass_enabled = false;
215 bool g_depthfillPass_enabled = false;
217 class GLSLBumpProgram : public GLProgram {
219 GLhandleARB m_program;
220 qtexture_t *m_light_attenuation_xy;
221 qtexture_t *m_light_attenuation_z;
223 GLint u_light_origin;
226 GLint u_specular_exponent;
228 GLSLBumpProgram() : m_program(0), m_light_attenuation_xy(0), m_light_attenuation_z(0)
235 m_program = glCreateProgramObjectARB();
239 StringOutputStream filename(256);
240 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.glsl";
241 createShader(m_program, filename.c_str(), GL_VERTEX_SHADER_ARB);
243 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glsl";
244 createShader(m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB);
247 GLSLProgram_link(m_program);
248 GLSLProgram_validate(m_program);
250 glUseProgramObjectARB(m_program);
252 glBindAttribLocationARB(m_program, c_attr_TexCoord0, "attr_TexCoord0");
253 glBindAttribLocationARB(m_program, c_attr_Tangent, "attr_Tangent");
254 glBindAttribLocationARB(m_program, c_attr_Binormal, "attr_Binormal");
256 glUniform1iARB(glGetUniformLocationARB(m_program, "u_diffusemap"), 0);
257 glUniform1iARB(glGetUniformLocationARB(m_program, "u_bumpmap"), 1);
258 glUniform1iARB(glGetUniformLocationARB(m_program, "u_specularmap"), 2);
259 glUniform1iARB(glGetUniformLocationARB(m_program, "u_attenuationmap_xy"), 3);
260 glUniform1iARB(glGetUniformLocationARB(m_program, "u_attenuationmap_z"), 4);
262 u_view_origin = glGetUniformLocationARB(m_program, "u_view_origin");
263 u_light_origin = glGetUniformLocationARB(m_program, "u_light_origin");
264 u_light_color = glGetUniformLocationARB(m_program, "u_light_color");
265 u_bump_scale = glGetUniformLocationARB(m_program, "u_bump_scale");
266 u_specular_exponent = glGetUniformLocationARB(m_program, "u_specular_exponent");
268 glUseProgramObjectARB(0);
270 GlobalOpenGL_debugAssertNoErrors();
275 glDeleteObjectARB(m_program);
281 glUseProgramObjectARB(m_program);
283 glEnableVertexAttribArrayARB(c_attr_TexCoord0);
284 glEnableVertexAttribArrayARB(c_attr_Tangent);
285 glEnableVertexAttribArrayARB(c_attr_Binormal);
287 GlobalOpenGL_debugAssertNoErrors();
289 debug_string("enable bump");
290 g_bumpGLSLPass_enabled = true;
295 glUseProgramObjectARB(0);
297 glDisableVertexAttribArrayARB(c_attr_TexCoord0);
298 glDisableVertexAttribArrayARB(c_attr_Tangent);
299 glDisableVertexAttribArrayARB(c_attr_Binormal);
301 GlobalOpenGL_debugAssertNoErrors();
303 debug_string("disable bump");
304 g_bumpGLSLPass_enabled = false;
307 void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
308 const Matrix4 &world2light)
310 Matrix4 world2local(localToWorld);
311 matrix4_affine_invert(world2local);
313 Vector3 localLight(origin);
314 matrix4_transform_point(world2local, localLight);
316 Vector3 localViewer(viewer);
317 matrix4_transform_point(world2local, localViewer);
319 Matrix4 local2light(world2light);
320 matrix4_multiply_by_matrix4(local2light, localToWorld); // local->world->light
322 glUniform3fARB(u_view_origin, localViewer.x(), localViewer.y(), localViewer.z());
323 glUniform3fARB(u_light_origin, localLight.x(), localLight.y(), localLight.z());
324 glUniform3fARB(u_light_color, colour.x(), colour.y(), colour.z());
325 glUniform1fARB(u_bump_scale, 1.0);
326 glUniform1fARB(u_specular_exponent, 32.0);
328 glActiveTexture(GL_TEXTURE3);
329 glClientActiveTexture(GL_TEXTURE3);
331 glMatrixMode(GL_TEXTURE);
332 glLoadMatrixf(reinterpret_cast<const float *>( &local2light ));
333 glMatrixMode(GL_MODELVIEW);
335 GlobalOpenGL_debugAssertNoErrors();
339 GLSLBumpProgram g_bumpGLSL;
342 class GLSLDepthFillProgram : public GLProgram {
344 GLhandleARB m_program;
349 m_program = glCreateProgramObjectARB();
353 StringOutputStream filename(256);
354 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glsl";
355 createShader(m_program, filename.c_str(), GL_VERTEX_SHADER_ARB);
357 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glsl";
358 createShader(m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB);
361 GLSLProgram_link(m_program);
362 GLSLProgram_validate(m_program);
364 GlobalOpenGL_debugAssertNoErrors();
369 glDeleteObjectARB(m_program);
375 glUseProgramObjectARB(m_program);
376 GlobalOpenGL_debugAssertNoErrors();
377 debug_string("enable depthfill");
378 g_depthfillPass_enabled = true;
383 glUseProgramObjectARB(0);
384 GlobalOpenGL_debugAssertNoErrors();
385 debug_string("disable depthfill");
386 g_depthfillPass_enabled = false;
389 void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
390 const Matrix4 &world2light)
395 GLSLDepthFillProgram g_depthFillGLSL;
400 void createProgram(const char *filename, GLenum type)
402 std::size_t size = file_size(filename);
403 FileInputStream file(filename);
404 ASSERT_MESSAGE(!file.failed(), "failed to open " << makeQuoted(filename));
405 Array<GLcharARB> buffer(size);
406 size = file.read(reinterpret_cast<StreamBase::byte_type *>( buffer.data()), size);
408 glProgramStringARB(type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei(size), buffer.data());
410 if (GL_INVALID_OPERATION == glGetError()) {
412 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
413 const GLubyte *errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
415 globalErrorStream() << reinterpret_cast<const char *>( filename ) << ":" << errPos << "\n"
416 << reinterpret_cast<const char *>( errString );
418 ERROR_MESSAGE("error in gl program");
422 class ARBBumpProgram : public GLProgram {
424 GLuint m_vertex_program;
425 GLuint m_fragment_program;
429 glEnable(GL_VERTEX_PROGRAM_ARB);
430 glEnable(GL_FRAGMENT_PROGRAM_ARB);
433 glGenProgramsARB(1, &m_vertex_program);
434 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertex_program);
435 StringOutputStream filename(256);
436 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.glp";
437 createProgram(filename.c_str(), GL_VERTEX_PROGRAM_ARB);
439 glGenProgramsARB(1, &m_fragment_program);
440 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
442 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glp";
443 createProgram(filename.c_str(), GL_FRAGMENT_PROGRAM_ARB);
446 glDisable(GL_VERTEX_PROGRAM_ARB);
447 glDisable(GL_FRAGMENT_PROGRAM_ARB);
449 GlobalOpenGL_debugAssertNoErrors();
454 glDeleteProgramsARB(1, &m_vertex_program);
455 glDeleteProgramsARB(1, &m_fragment_program);
456 GlobalOpenGL_debugAssertNoErrors();
461 glEnable(GL_VERTEX_PROGRAM_ARB);
462 glEnable(GL_FRAGMENT_PROGRAM_ARB);
463 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertex_program);
464 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
466 glEnableVertexAttribArrayARB(8);
467 glEnableVertexAttribArrayARB(9);
468 glEnableVertexAttribArrayARB(10);
469 glEnableVertexAttribArrayARB(11);
471 GlobalOpenGL_debugAssertNoErrors();
476 glDisable(GL_VERTEX_PROGRAM_ARB);
477 glDisable(GL_FRAGMENT_PROGRAM_ARB);
479 glDisableVertexAttribArrayARB(8);
480 glDisableVertexAttribArrayARB(9);
481 glDisableVertexAttribArrayARB(10);
482 glDisableVertexAttribArrayARB(11);
484 GlobalOpenGL_debugAssertNoErrors();
487 void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
488 const Matrix4 &world2light)
490 Matrix4 world2local(localToWorld);
491 matrix4_affine_invert(world2local);
493 Vector3 localLight(origin);
494 matrix4_transform_point(world2local, localLight);
496 Vector3 localViewer(viewer);
497 matrix4_transform_point(world2local, localViewer);
499 Matrix4 local2light(world2light);
500 matrix4_multiply_by_matrix4(local2light, localToWorld); // local->world->light
503 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0);
506 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1);
509 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0);
512 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0);
515 glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0);
518 glActiveTexture(GL_TEXTURE3);
519 glClientActiveTexture(GL_TEXTURE3);
521 glMatrixMode(GL_TEXTURE);
522 glLoadMatrixf(reinterpret_cast<const float *>( &local2light ));
523 glMatrixMode(GL_MODELVIEW);
525 GlobalOpenGL_debugAssertNoErrors();
529 class ARBDepthFillProgram : public GLProgram {
531 GLuint m_vertex_program;
532 GLuint m_fragment_program;
536 glEnable(GL_VERTEX_PROGRAM_ARB);
537 glEnable(GL_FRAGMENT_PROGRAM_ARB);
540 glGenProgramsARB(1, &m_vertex_program);
541 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertex_program);
542 StringOutputStream filename(256);
543 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glp";
544 createProgram(filename.c_str(), GL_VERTEX_PROGRAM_ARB);
546 glGenProgramsARB(1, &m_fragment_program);
547 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
549 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glp";
550 createProgram(filename.c_str(), GL_FRAGMENT_PROGRAM_ARB);
553 glDisable(GL_VERTEX_PROGRAM_ARB);
554 glDisable(GL_FRAGMENT_PROGRAM_ARB);
556 GlobalOpenGL_debugAssertNoErrors();
561 glDeleteProgramsARB(1, &m_vertex_program);
562 glDeleteProgramsARB(1, &m_fragment_program);
563 GlobalOpenGL_debugAssertNoErrors();
568 glEnable(GL_VERTEX_PROGRAM_ARB);
569 glEnable(GL_FRAGMENT_PROGRAM_ARB);
570 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertex_program);
571 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
573 GlobalOpenGL_debugAssertNoErrors();
578 glDisable(GL_VERTEX_PROGRAM_ARB);
579 glDisable(GL_FRAGMENT_PROGRAM_ARB);
581 GlobalOpenGL_debugAssertNoErrors();
584 void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
585 const Matrix4 &world2light)
590 ARBBumpProgram g_bumpARB;
591 ARBDepthFillProgram g_depthFillARB;
595 // NV20 path (unfinished)
597 void createProgram( GLint program, const char* filename, GLenum type ){
598 std::size_t size = file_size( filename );
599 FileInputStream file( filename );
600 ASSERT_MESSAGE( !file.failed(), "failed to open " << makeQuoted( filename ) );
601 Array<GLubyte> buffer( size );
602 size = file.read( reinterpret_cast<StreamBase::byte_type*>( buffer.data() ), size );
604 glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
606 if ( GL_INVALID_OPERATION == glGetError() ) {
608 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
609 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
611 globalErrorStream() << filename << ":" << errPos << "\n" << errString;
613 ERROR_MESSAGE( "error in gl program" );
617 GLuint m_vertex_program;
618 GLuint m_fragment_program;
619 qtexture_t* g_cube = 0;
620 qtexture_t* g_specular_lookup = 0;
621 qtexture_t* g_attenuation_xy = 0;
622 qtexture_t* g_attenuation_z = 0;
624 void createVertexProgram(){
626 glGenProgramsNV( 1, &m_vertex_program );
627 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
628 StringOutputStream filename( 256 );
629 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_vp.nv30";
630 createProgram( m_vertex_program, filename.c_str(), GL_VERTEX_PROGRAM_NV );
632 glGenProgramsNV( 1, &m_fragment_program );
633 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
635 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.nv30";
636 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
639 g_cube = GlobalTexturesCache().capture( "generated/cube" );
640 g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
642 g_attenuation_xy = GlobalTexturesCache().capture( "lights/squarelight1" );
643 glActiveTexture( GL_TEXTURE0 );
644 glBindTexture( GL_TEXTURE_2D, g_attenuation_xy->texture_number );
645 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
646 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
648 g_attenuation_z = GlobalTexturesCache().capture( "lights/squarelight1a" );
649 glActiveTexture( GL_TEXTURE0 );
650 glBindTexture( GL_TEXTURE_2D, g_attenuation_z->texture_number );
651 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
652 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
654 GlobalOpenGL_debugAssertNoErrors();
657 void destroyVertexProgram(){
658 glDeleteProgramsNV( 1, &m_vertex_program );
659 glDeleteProgramsNV( 1, &m_fragment_program );
660 GlobalOpenGL_debugAssertNoErrors();
662 GlobalTexturesCache().release( g_cube );
663 GlobalTexturesCache().release( g_specular_lookup );
664 GlobalTexturesCache().release( g_attenuation_xy );
665 GlobalTexturesCache().release( g_attenuation_z );
668 bool g_vertexProgram_enabled = false;
670 void enableVertexProgram(){
671 //set up the register combiners
672 //two general combiners
673 glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
675 //combiner 0 does tex0+tex1 -> spare0
676 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB,
677 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
678 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
679 GL_UNSIGNED_INVERT_NV, GL_RGB );
680 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB,
681 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
682 glCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
683 GL_UNSIGNED_INVERT_NV, GL_RGB );
684 glCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV,
685 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
687 //combiner 1 does tex2 dot tex3 -> spare1
688 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE2_ARB,
689 GL_EXPAND_NORMAL_NV, GL_RGB );
690 glCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE3_ARB,
691 GL_EXPAND_NORMAL_NV, GL_RGB );
692 glCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
693 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
697 //final combiner outputs (1-spare0)*constant color 0*spare1
698 //do constant color 0*spare1 in the EF multiplier
699 glFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
700 glFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
702 //now do (1-spare0)*EF
703 glFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
704 glFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
705 glFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
706 glFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
708 glEnable( GL_VERTEX_PROGRAM_NV );
709 glEnable( GL_REGISTER_COMBINERS_NV );
710 glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
711 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
713 glActiveTexture( GL_TEXTURE0 );
714 glEnable( GL_TEXTURE_2D );
715 glActiveTexture( GL_TEXTURE1 );
716 glEnable( GL_TEXTURE_1D );
717 glActiveTexture( GL_TEXTURE2 );
718 glEnable( GL_TEXTURE_2D );
719 glActiveTexture( GL_TEXTURE3 );
720 glEnable( GL_TEXTURE_2D );
722 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
723 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
724 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
725 glEnableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
727 GlobalOpenGL_debugAssertNoErrors();
728 g_vertexProgram_enabled = true;
731 void disableVertexProgram(){
732 glDisable( GL_VERTEX_PROGRAM_NV );
733 glDisable( GL_REGISTER_COMBINERS_NV );
735 glActiveTexture( GL_TEXTURE0 );
736 glDisable( GL_TEXTURE_2D );
737 glActiveTexture( GL_TEXTURE1 );
738 glDisable( GL_TEXTURE_1D );
739 glActiveTexture( GL_TEXTURE2 );
740 glDisable( GL_TEXTURE_2D );
741 glActiveTexture( GL_TEXTURE3 );
742 glDisable( GL_TEXTURE_2D );
744 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY8_NV );
745 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY9_NV );
746 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY10_NV );
747 glDisableClientState( GL_VERTEX_ATTRIB_ARRAY11_NV );
749 GlobalOpenGL_debugAssertNoErrors();
750 g_vertexProgram_enabled = false;
756 const GLubyte* m_string;
757 const GLint m_length;
758 GLstringNV( const char* string ) : m_string( reinterpret_cast<const GLubyte*>( string ) ), m_length( GLint( string_length( string ) ) ){
762 GLstringNV g_light_origin( "light_origin" );
763 GLstringNV g_view_origin( "view_origin" );
764 GLstringNV g_light_color( "light_color" );
765 GLstringNV g_bumpGLSL_scale( "bump_scale" );
766 GLstringNV g_specular_exponent( "specular_exponent" );
768 void setVertexProgramEnvironment( const Vector3& localViewer ){
769 Matrix4 local2light( g_matrix4_identity );
770 matrix4_translate_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
771 matrix4_scale_by_vec3( local2light, Vector3( 0.5, 0.5, 0.5 ) );
772 matrix4_scale_by_vec3( local2light, Vector3( 1.0 / 512.0, 1.0 / 512.0, 1.0 / 512.0 ) );
773 matrix4_translate_by_vec3( local2light, vector3_negated( localViewer ) );
775 glActiveTexture( GL_TEXTURE3 );
776 glClientActiveTexture( GL_TEXTURE3 );
778 glMatrixMode( GL_TEXTURE );
779 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
780 glMatrixMode( GL_MODELVIEW );
782 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV );
783 glTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 4, GL_TEXTURE0_ARB, GL_IDENTITY_NV );
786 //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
789 glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
792 glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
795 //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
798 //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
800 GlobalOpenGL_debugAssertNoErrors();
806 bool g_vertexArray_enabled = false;
807 bool g_normalArray_enabled = false;
808 bool g_texcoordArray_enabled = false;
809 bool g_colorArray_enabled = false;
811 inline bool OpenGLState_less(const OpenGLState &self, const OpenGLState &other)
813 //! Sort by sort-order override.
814 if (self.m_sort != other.m_sort) {
815 return self.m_sort < other.m_sort;
817 //! Sort by texture handle.
818 if (self.m_texture != other.m_texture) {
819 return self.m_texture < other.m_texture;
821 if (self.m_texture1 != other.m_texture1) {
822 return self.m_texture1 < other.m_texture1;
824 if (self.m_texture2 != other.m_texture2) {
825 return self.m_texture2 < other.m_texture2;
827 if (self.m_texture3 != other.m_texture3) {
828 return self.m_texture3 < other.m_texture3;
830 if (self.m_texture4 != other.m_texture4) {
831 return self.m_texture4 < other.m_texture4;
833 if (self.m_texture5 != other.m_texture5) {
834 return self.m_texture5 < other.m_texture5;
836 if (self.m_texture6 != other.m_texture6) {
837 return self.m_texture6 < other.m_texture6;
839 if (self.m_texture7 != other.m_texture7) {
840 return self.m_texture7 < other.m_texture7;
842 //! Sort by state bit-vector.
843 if (self.m_state != other.m_state) {
844 return self.m_state < other.m_state;
846 //! Comparing address makes sure states are never equal.
847 return &self < &other;
850 void OpenGLState_constructDefault(OpenGLState &state)
852 state.m_state = RENDER_DEFAULT;
855 state.m_texture1 = 0;
856 state.m_texture2 = 0;
857 state.m_texture3 = 0;
858 state.m_texture4 = 0;
859 state.m_texture5 = 0;
860 state.m_texture6 = 0;
861 state.m_texture7 = 0;
863 state.m_colour[0] = 1;
864 state.m_colour[1] = 1;
865 state.m_colour[2] = 1;
866 state.m_colour[3] = 1;
868 state.m_depthfunc = GL_LESS;
870 state.m_blend_src = GL_SRC_ALPHA;
871 state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
873 state.m_alphafunc = GL_ALWAYS;
874 state.m_alpharef = 0;
876 state.m_linewidth = 1;
877 state.m_pointsize = 1;
879 state.m_linestipple_factor = 1;
880 state.m_linestipple_pattern = 0xaaaa;
882 state.m_fog = OpenGLFogState();
886 /// \brief A container of Renderable references.
887 /// May contain the same Renderable multiple times, with different transforms.
888 class OpenGLStateBucket {
890 struct RenderTransform {
891 const Matrix4 *m_transform;
892 const OpenGLRenderable *m_renderable;
893 const RendererLight *m_light;
895 RenderTransform(const OpenGLRenderable &renderable, const Matrix4 &transform, const RendererLight *light)
896 : m_transform(&transform), m_renderable(&renderable), m_light(light)
901 typedef std::vector<RenderTransform> Renderables;
906 Renderables m_renderables;
913 void addRenderable(const OpenGLRenderable &renderable, const Matrix4 &modelview, const RendererLight *light = 0)
915 m_renderables.push_back(RenderTransform(renderable, modelview, light));
923 void render(OpenGLState ¤t, unsigned int globalstate, const Vector3 &viewer);
926 #define LIGHT_SHADER_DEBUG 0
928 #if LIGHT_SHADER_DEBUG
929 typedef std::vector<Shader*> LightDebugShaders;
930 LightDebugShaders g_lightDebugShaders;
933 class OpenGLStateLess {
935 bool operator()(const OpenGLState &self, const OpenGLState &other) const
937 return OpenGLState_less(self, other);
941 typedef ConstReference<OpenGLState> OpenGLStateReference;
942 typedef std::map<OpenGLStateReference, OpenGLStateBucket *, OpenGLStateLess> OpenGLStates;
943 OpenGLStates g_state_sorted;
945 class OpenGLStateBucketAdd {
946 OpenGLStateBucket &m_bucket;
947 const OpenGLRenderable &m_renderable;
948 const Matrix4 &m_modelview;
950 using func = void(const RendererLight &);
952 OpenGLStateBucketAdd(OpenGLStateBucket &bucket, const OpenGLRenderable &renderable, const Matrix4 &modelview) :
953 m_bucket(bucket), m_renderable(renderable), m_modelview(modelview)
957 void operator()(const RendererLight &light)
959 m_bucket.addRenderable(m_renderable, m_modelview, &light);
966 using func = void(RendererLight &);
968 CountLights() : m_count(0)
972 void operator()(const RendererLight &light)
977 std::size_t count() const
983 class OpenGLShader : public Shader {
984 typedef std::list<OpenGLStateBucket *> Passes;
988 ModuleObservers m_observers;
990 OpenGLShader() : m_shader(0), m_used(0)
998 void construct(const char *name);
1007 for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1013 void addRenderable(const OpenGLRenderable &renderable, const Matrix4 &modelview, const LightList *lights)
1015 for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1016 #if LIGHT_SHADER_DEBUG
1017 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
1018 if ( lights != 0 ) {
1019 CountLights counter;
1020 lights->forEachLight( makeCallback1( counter ) );
1021 globalOutputStream() << "count = " << counter.count() << "\n";
1022 for ( std::size_t i = 0; i < counter.count(); ++i )
1024 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
1030 if (((*i)->state().m_state & RENDER_BUMP) != 0) {
1032 OpenGLStateBucketAdd add(*(*i), renderable, modelview);
1033 lights->forEachLight(makeCallback(add));
1038 (*i)->addRenderable(renderable, modelview);
1043 void incrementUsed()
1045 if (++m_used == 1 && m_shader != 0) {
1046 m_shader->SetInUse(true);
1050 void decrementUsed()
1052 if (--m_used == 0 && m_shader != 0) {
1053 m_shader->SetInUse(false);
1057 bool realised() const
1059 return m_shader != 0;
1062 void attach(ModuleObserver &observer)
1067 m_observers.attach(observer);
1070 void detach(ModuleObserver &observer)
1073 observer.unrealise();
1075 m_observers.detach(observer);
1078 void realise(const CopiedString &name)
1080 construct(name.c_str());
1082 if (m_used != 0 && m_shader != 0) {
1083 m_shader->SetInUse(true);
1086 for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1087 g_state_sorted.insert(OpenGLStates::value_type(OpenGLStateReference((*i)->state()), *i));
1090 m_observers.realise();
1095 m_observers.unrealise();
1097 for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1098 g_state_sorted.erase(OpenGLStateReference((*i)->state()));
1104 qtexture_t &getTexture() const
1106 ASSERT_NOTNULL(m_shader);
1107 return *m_shader->getTexture();
1110 unsigned int getFlags() const
1112 ASSERT_NOTNULL(m_shader);
1113 return m_shader->getFlags();
1116 IShader &getShader() const
1118 ASSERT_NOTNULL(m_shader);
1122 OpenGLState &appendDefaultPass()
1124 m_passes.push_back(new OpenGLStateBucket);
1125 OpenGLState &state = m_passes.back()->state();
1126 OpenGLState_constructDefault(state);
1132 inline bool lightEnabled(const RendererLight &light, const LightCullable &cullable)
1134 return cullable.testLight(light);
1137 typedef std::set<RendererLight *> RendererLights;
1139 #define DEBUG_LIGHT_SYNC 0
1141 class LinearLightList : public LightList {
1142 LightCullable &m_cullable;
1143 RendererLights &m_allLights;
1144 Callback<void()> m_evaluateChanged;
1146 typedef std::list<RendererLight *> Lights;
1147 mutable Lights m_lights;
1148 mutable bool m_lightsChanged;
1150 LinearLightList(LightCullable &cullable, RendererLights &lights, const Callback<void()> &evaluateChanged) :
1151 m_cullable(cullable), m_allLights(lights), m_evaluateChanged(evaluateChanged)
1153 m_lightsChanged = true;
1156 void evaluateLights() const
1158 m_evaluateChanged();
1159 if (m_lightsChanged) {
1160 m_lightsChanged = false;
1163 m_cullable.clearLights();
1164 for (RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i) {
1165 if (lightEnabled(*(*i), m_cullable)) {
1166 m_lights.push_back(*i);
1167 m_cullable.insertLight(*(*i));
1171 #if (DEBUG_LIGHT_SYNC)
1175 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1177 if ( lightEnabled( *( *i ), m_cullable ) ) {
1178 lights.push_back( *i );
1182 !std::lexicographical_compare( lights.begin(), lights.end(), m_lights.begin(), m_lights.end() )
1183 && !std::lexicographical_compare( m_lights.begin(), m_lights.end(), lights.begin(), lights.end() ),
1184 "lights out of sync"
1190 void forEachLight(const RendererLightCallback &callback) const
1194 for (Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) {
1199 void lightsChanged() const
1201 m_lightsChanged = true;
1205 inline void setFogState(const OpenGLFogState &state)
1207 glFogi(GL_FOG_MODE, state.mode);
1208 glFogf(GL_FOG_DENSITY, state.density);
1209 glFogf(GL_FOG_START, state.start);
1210 glFogf(GL_FOG_END, state.end);
1211 glFogi(GL_FOG_INDEX, state.index);
1212 glFogfv(GL_FOG_COLOR, vector4_to_array(state.colour));
1215 #define DEBUG_SHADERS 0
1217 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver {
1218 class CreateOpenGLShader {
1219 OpenGLShaderCache *m_cache;
1221 explicit CreateOpenGLShader(OpenGLShaderCache *cache = 0)
1226 OpenGLShader *construct(const CopiedString &name)
1228 OpenGLShader *shader = new OpenGLShader;
1229 if (m_cache->realised()) {
1230 shader->realise(name);
1235 void destroy(OpenGLShader *shader)
1237 if (m_cache->realised()) {
1238 shader->unrealise();
1244 typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1246 std::size_t m_unrealised;
1248 bool m_lightingEnabled;
1249 bool m_lightingSupported;
1250 bool m_useShaderLanguage;
1254 : m_shaders(CreateOpenGLShader(this)),
1256 3), // wait until shaders, gl-context and textures are realised before creating any render-states
1257 m_lightingEnabled(true),
1258 m_lightingSupported(false),
1259 m_useShaderLanguage(false),
1260 m_lightsChanged(true),
1261 m_traverseRenderablesMutex(false)
1265 ~OpenGLShaderCache()
1267 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
1268 globalOutputStream() << "leaked shader: " << makeQuoted((*i).key.c_str()) << "\n";
1272 Shader *capture(const char *name)
1274 ASSERT_MESSAGE(name[0] == '$'
1278 || strchr(name, '\\') == 0, "shader name contains invalid characters: \"" << name << "\"");
1280 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1282 return m_shaders.capture(name).get();
1285 void release(const char *name)
1288 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1290 m_shaders.release(name);
1294 render(RenderStateFlags globalstate, const Matrix4 &modelview, const Matrix4 &projection, const Vector3 &viewer)
1296 glMatrixMode(GL_PROJECTION);
1297 glLoadMatrixf(reinterpret_cast<const float *>( &projection ));
1299 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1302 glMatrixMode(GL_MODELVIEW);
1303 glLoadMatrixf(reinterpret_cast<const float *>( &modelview ));
1305 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1308 ASSERT_MESSAGE(realised(), "render states are not realised");
1310 // global settings that are not set in renderstates
1312 glCullFace(GL_BACK);
1313 glPolygonOffset(-1, 1);
1315 const GLubyte pattern[132] = {
1316 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1317 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1318 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1319 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1320 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1321 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1322 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1323 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1324 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1325 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1326 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1327 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1328 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1329 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1330 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
1331 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
1333 glPolygonStipple(pattern);
1335 glEnableClientState(GL_VERTEX_ARRAY);
1336 g_vertexArray_enabled = true;
1337 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
1339 if (GlobalOpenGL().GL_1_3()) {
1340 glActiveTexture(GL_TEXTURE0);
1341 glClientActiveTexture(GL_TEXTURE0);
1344 if (GlobalOpenGL().ARB_shader_objects()) {
1345 glUseProgramObjectARB(0);
1346 glDisableVertexAttribArrayARB(c_attr_TexCoord0);
1347 glDisableVertexAttribArrayARB(c_attr_Tangent);
1348 glDisableVertexAttribArrayARB(c_attr_Binormal);
1351 if (globalstate & RENDER_TEXTURE) {
1352 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1353 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1356 OpenGLState current;
1357 OpenGLState_constructDefault(current);
1358 current.m_sort = OpenGLState::eSortFirst;
1360 // default renderstate settings
1361 glLineStipple(current.m_linestipple_factor, current.m_linestipple_pattern);
1362 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1363 glDisable(GL_LIGHTING);
1364 glDisable(GL_TEXTURE_2D);
1365 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1366 g_texcoordArray_enabled = false;
1367 glDisableClientState(GL_COLOR_ARRAY);
1368 g_colorArray_enabled = false;
1369 glDisableClientState(GL_NORMAL_ARRAY);
1370 g_normalArray_enabled = false;
1371 glDisable(GL_BLEND);
1372 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1373 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1374 glDisable(GL_CULL_FACE);
1375 glShadeModel(GL_FLAT);
1376 glDisable(GL_DEPTH_TEST);
1377 glDepthMask(GL_FALSE);
1378 glDisable(GL_ALPHA_TEST);
1379 glDisable(GL_LINE_STIPPLE);
1380 glDisable(GL_POLYGON_STIPPLE);
1381 glDisable(GL_POLYGON_OFFSET_LINE);
1383 glBindTexture(GL_TEXTURE_2D, 0);
1384 glColor4f(1, 1, 1, 1);
1385 glDepthFunc(GL_LESS);
1386 glAlphaFunc(GL_ALWAYS, 0);
1390 glHint(GL_FOG_HINT, GL_NICEST);
1392 setFogState(OpenGLFogState());
1394 GlobalOpenGL_debugAssertNoErrors();
1396 debug_string("begin rendering");
1397 for (OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i) {
1398 (*i).second->render(current, globalstate, viewer);
1400 debug_string("end rendering");
1405 if (--m_unrealised == 0) {
1406 if (lightingSupported() && lightingEnabled()) {
1407 if (useShaderLanguage()) {
1408 g_bumpGLSL.create();
1409 g_depthFillGLSL.create();
1412 g_depthFillARB.create();
1416 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
1417 if (!(*i).value.empty()) {
1418 (*i).value->realise(i->key);
1426 if (++m_unrealised == 1) {
1427 for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
1428 if (!(*i).value.empty()) {
1429 (*i).value->unrealise();
1432 if (GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled()) {
1433 if (useShaderLanguage()) {
1434 g_bumpGLSL.destroy();
1435 g_depthFillGLSL.destroy();
1437 g_bumpARB.destroy();
1438 g_depthFillARB.destroy();
1446 return m_unrealised == 0;
1450 bool lightingEnabled() const
1452 return m_lightingEnabled;
1455 bool lightingSupported() const
1457 return m_lightingSupported;
1460 bool useShaderLanguage() const
1462 return m_useShaderLanguage;
1465 void setLighting(bool supported, bool enabled)
1467 bool refresh = (m_lightingSupported && m_lightingEnabled) != (supported && enabled);
1471 GlobalShaderSystem().setLightingEnabled(supported && enabled);
1474 m_lightingSupported = supported;
1475 m_lightingEnabled = enabled;
1482 void extensionsInitialised()
1484 setLighting(GlobalOpenGL().GL_1_3()
1485 && GlobalOpenGL().ARB_vertex_program()
1486 && GlobalOpenGL().ARB_fragment_program()
1487 && GlobalOpenGL().ARB_shader_objects()
1488 && GlobalOpenGL().ARB_vertex_shader()
1489 && GlobalOpenGL().ARB_fragment_shader()
1490 && GlobalOpenGL().ARB_shading_language_100(),
1494 if (!lightingSupported()) {
1495 globalOutputStream() << "Lighting mode requires OpenGL features not supported by your graphics drivers:\n";
1496 if (!GlobalOpenGL().GL_1_3()) {
1497 globalOutputStream() << " GL version 1.3 or better\n";
1499 if (!GlobalOpenGL().ARB_vertex_program()) {
1500 globalOutputStream() << " GL_ARB_vertex_program\n";
1502 if (!GlobalOpenGL().ARB_fragment_program()) {
1503 globalOutputStream() << " GL_ARB_fragment_program\n";
1505 if (!GlobalOpenGL().ARB_shader_objects()) {
1506 globalOutputStream() << " GL_ARB_shader_objects\n";
1508 if (!GlobalOpenGL().ARB_vertex_shader()) {
1509 globalOutputStream() << " GL_ARB_vertex_shader\n";
1511 if (!GlobalOpenGL().ARB_fragment_shader()) {
1512 globalOutputStream() << " GL_ARB_fragment_shader\n";
1514 if (!GlobalOpenGL().ARB_shading_language_100()) {
1515 globalOutputStream() << " GL_ARB_shading_language_100\n";
1520 void setLightingEnabled(bool enabled)
1522 setLighting(m_lightingSupported, enabled);
1527 RendererLights m_lights;
1528 bool m_lightsChanged;
1529 typedef std::map<LightCullable *, LinearLightList> LightLists;
1530 LightLists m_lightLists;
1532 const LightList &attach(LightCullable &cullable)
1534 return (*m_lightLists.insert(LightLists::value_type(&cullable, LinearLightList(cullable, m_lights,
1535 EvaluateChangedCaller(
1536 *this)))).first).second;
1539 void detach(LightCullable &cullable)
1541 m_lightLists.erase(&cullable);
1544 void changed(LightCullable &cullable)
1546 LightLists::iterator i = m_lightLists.find(&cullable);
1547 ASSERT_MESSAGE(i != m_lightLists.end(), "cullable not attached");
1548 (*i).second.lightsChanged();
1551 void attach(RendererLight &light)
1553 ASSERT_MESSAGE(m_lights.find(&light) == m_lights.end(), "light could not be attached");
1554 m_lights.insert(&light);
1558 void detach(RendererLight &light)
1560 ASSERT_MESSAGE(m_lights.find(&light) != m_lights.end(), "light could not be detached");
1561 m_lights.erase(&light);
1565 void changed(RendererLight &light)
1567 m_lightsChanged = true;
1570 void evaluateChanged()
1572 if (m_lightsChanged) {
1573 m_lightsChanged = false;
1574 for (LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i) {
1575 (*i).second.lightsChanged();
1580 typedef MemberCaller<OpenGLShaderCache, void(), &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1582 typedef std::set<const Renderable *> Renderables;
1583 Renderables m_renderables;
1584 mutable bool m_traverseRenderablesMutex;
1587 void attachRenderable(const Renderable &renderable)
1589 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "attaching renderable during traversal");
1590 ASSERT_MESSAGE(m_renderables.find(&renderable) == m_renderables.end(), "renderable could not be attached");
1591 m_renderables.insert(&renderable);
1594 void detachRenderable(const Renderable &renderable)
1596 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "detaching renderable during traversal");
1597 ASSERT_MESSAGE(m_renderables.find(&renderable) != m_renderables.end(), "renderable could not be detached");
1598 m_renderables.erase(&renderable);
1601 void forEachRenderable(const RenderableCallback &callback) const
1603 ASSERT_MESSAGE(!m_traverseRenderablesMutex, "for-each during traversal");
1604 m_traverseRenderablesMutex = true;
1605 for (Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i) {
1608 m_traverseRenderablesMutex = false;
1612 static OpenGLShaderCache *g_ShaderCache;
1614 void ShaderCache_extensionsInitialised()
1616 g_ShaderCache->extensionsInitialised();
1619 void ShaderCache_setBumpEnabled(bool enabled)
1621 g_ShaderCache->setLightingEnabled(enabled);
1625 Vector3 g_DebugShaderColours[256];
1626 Shader *g_defaultPointLight = 0;
1628 void ShaderCache_Construct()
1630 g_ShaderCache = new OpenGLShaderCache;
1631 GlobalTexturesCache().attach(*g_ShaderCache);
1632 GlobalShaderSystem().attach(*g_ShaderCache);
1634 if (g_pGameDescription->mGameType == "doom3") {
1635 g_defaultPointLight = g_ShaderCache->capture("lights/defaultPointLight");
1636 //Shader* overbright =
1637 g_ShaderCache->capture("$OVERBRIGHT");
1639 #if LIGHT_SHADER_DEBUG
1640 for ( std::size_t i = 0; i < 256; ++i )
1642 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1645 g_DebugShaderColours[0] = Vector3( 1, 0, 0 );
1646 g_DebugShaderColours[1] = Vector3( 1, 0.5, 0 );
1647 g_DebugShaderColours[2] = Vector3( 1, 1, 0 );
1648 g_DebugShaderColours[3] = Vector3( 0.5, 1, 0 );
1649 g_DebugShaderColours[4] = Vector3( 0, 1, 0 );
1650 g_DebugShaderColours[5] = Vector3( 0, 1, 0.5 );
1651 g_DebugShaderColours[6] = Vector3( 0, 1, 1 );
1652 g_DebugShaderColours[7] = Vector3( 0, 0.5, 1 );
1653 g_DebugShaderColours[8] = Vector3( 0, 0, 1 );
1654 g_DebugShaderColours[9] = Vector3( 0.5, 0, 1 );
1655 g_DebugShaderColours[10] = Vector3( 1, 0, 1 );
1656 g_DebugShaderColours[11] = Vector3( 1, 0, 0.5 );
1658 g_lightDebugShaders.reserve( 256 );
1659 StringOutputStream buffer( 256 );
1660 for ( std::size_t i = 0; i < 256; ++i )
1662 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1663 g_lightDebugShaders.push_back( g_ShaderCache->capture( buffer.c_str() ) );
1670 void ShaderCache_Destroy()
1672 if (g_pGameDescription->mGameType == "doom3") {
1673 g_ShaderCache->release("lights/defaultPointLight");
1674 g_ShaderCache->release("$OVERBRIGHT");
1675 g_defaultPointLight = 0;
1677 #if LIGHT_SHADER_DEBUG
1678 g_lightDebugShaders.clear();
1679 StringOutputStream buffer( 256 );
1680 for ( std::size_t i = 0; i < 256; ++i )
1682 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1683 g_ShaderCache->release( buffer.c_str() );
1688 GlobalShaderSystem().detach(*g_ShaderCache);
1689 GlobalTexturesCache().detach(*g_ShaderCache);
1690 delete g_ShaderCache;
1693 ShaderCache *GetShaderCache()
1695 return g_ShaderCache;
1698 inline void setTextureState(GLint ¤t, const GLint &texture, GLenum textureUnit)
1700 if (texture != current) {
1701 glActiveTexture(textureUnit);
1702 glClientActiveTexture(textureUnit);
1703 glBindTexture(GL_TEXTURE_2D, texture);
1704 GlobalOpenGL_debugAssertNoErrors();
1709 inline void setTextureState(GLint ¤t, const GLint &texture)
1711 if (texture != current) {
1712 glBindTexture(GL_TEXTURE_2D, texture);
1713 GlobalOpenGL_debugAssertNoErrors();
1718 inline void setState(unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag)
1720 if (delta & state & flag) {
1722 GlobalOpenGL_debugAssertNoErrors();
1723 } else if (delta & ~state & flag) {
1725 GlobalOpenGL_debugAssertNoErrors();
1729 void OpenGLState_apply(const OpenGLState &self, OpenGLState ¤t, unsigned int globalstate)
1731 debug_int("sort", int(self.m_sort));
1732 debug_int("texture", self.m_texture);
1733 debug_int("state", self.m_state);
1734 debug_int("address", int(std::size_t(&self)));
1738 if (self.m_state & RENDER_OVERRIDE) {
1739 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1742 const unsigned int state = self.m_state & globalstate;
1743 const unsigned int delta = state ^current.m_state;
1745 GlobalOpenGL_debugAssertNoErrors();
1747 GLProgram *program = (state & RENDER_PROGRAM) != 0 ? self.m_program : 0;
1749 if (program != current.m_program) {
1750 if (current.m_program != 0) {
1751 current.m_program->disable();
1752 glColor4fv(vector4_to_array(current.m_colour));
1753 debug_colour("cleaning program");
1756 current.m_program = program;
1758 if (current.m_program != 0) {
1759 current.m_program->enable();
1763 if (delta & state & RENDER_FILL) {
1764 //qglPolygonMode (GL_BACK, GL_LINE);
1765 //qglPolygonMode (GL_FRONT, GL_FILL);
1766 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1767 GlobalOpenGL_debugAssertNoErrors();
1768 } else if (delta & ~state & RENDER_FILL) {
1769 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1770 GlobalOpenGL_debugAssertNoErrors();
1773 setState(state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE);
1775 if (delta & state & RENDER_LIGHTING) {
1776 glEnable(GL_LIGHTING);
1777 glEnable(GL_COLOR_MATERIAL);
1778 glEnable(GL_RESCALE_NORMAL);
1779 glEnableClientState(GL_NORMAL_ARRAY);
1780 GlobalOpenGL_debugAssertNoErrors();
1781 g_normalArray_enabled = true;
1782 } else if (delta & ~state & RENDER_LIGHTING) {
1783 glDisable(GL_LIGHTING);
1784 glDisable(GL_COLOR_MATERIAL);
1785 glDisable(GL_RESCALE_NORMAL);
1786 glDisableClientState(GL_NORMAL_ARRAY);
1787 GlobalOpenGL_debugAssertNoErrors();
1788 g_normalArray_enabled = false;
1791 if (delta & state & RENDER_TEXTURE) {
1792 GlobalOpenGL_debugAssertNoErrors();
1794 if (GlobalOpenGL().GL_1_3()) {
1795 glActiveTexture(GL_TEXTURE0);
1796 glClientActiveTexture(GL_TEXTURE0);
1799 glEnable(GL_TEXTURE_2D);
1801 glColor4f(1, 1, 1, self.m_colour[3]);
1802 debug_colour("setting texture");
1804 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1805 GlobalOpenGL_debugAssertNoErrors();
1806 g_texcoordArray_enabled = true;
1807 } else if (delta & ~state & RENDER_TEXTURE) {
1808 if (GlobalOpenGL().GL_1_3()) {
1809 glActiveTexture(GL_TEXTURE0);
1810 glClientActiveTexture(GL_TEXTURE0);
1813 glDisable(GL_TEXTURE_2D);
1814 glBindTexture(GL_TEXTURE_2D, 0);
1815 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1817 GlobalOpenGL_debugAssertNoErrors();
1818 g_texcoordArray_enabled = false;
1821 if (delta & state & RENDER_BLEND) {
1822 // FIXME: some .TGA are buggy, have a completely empty alpha channel
1823 // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE
1824 // so I decided using GL_DECAL instead
1825 // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent.
1826 // this could get better if you can get glTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome
1829 if (GlobalOpenGL().GL_1_3()) {
1830 glActiveTexture(GL_TEXTURE0);
1832 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1833 GlobalOpenGL_debugAssertNoErrors();
1834 } else if (delta & ~state & RENDER_BLEND) {
1835 glDisable(GL_BLEND);
1836 if (GlobalOpenGL().GL_1_3()) {
1837 glActiveTexture(GL_TEXTURE0);
1839 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1840 GlobalOpenGL_debugAssertNoErrors();
1843 setState(state, delta, RENDER_CULLFACE, GL_CULL_FACE);
1845 if (delta & state & RENDER_SMOOTH) {
1846 glShadeModel(GL_SMOOTH);
1847 GlobalOpenGL_debugAssertNoErrors();
1848 } else if (delta & ~state & RENDER_SMOOTH) {
1849 glShadeModel(GL_FLAT);
1850 GlobalOpenGL_debugAssertNoErrors();
1853 setState(state, delta, RENDER_SCALED, GL_NORMALIZE); // not GL_RESCALE_NORMAL
1855 setState(state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST);
1857 if (delta & state & RENDER_DEPTHWRITE) {
1858 glDepthMask(GL_TRUE);
1861 GLboolean depthEnabled;
1862 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1863 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1865 debug_string("enabled depth-buffer writing");
1867 GlobalOpenGL_debugAssertNoErrors();
1868 } else if (delta & ~state & RENDER_DEPTHWRITE) {
1869 glDepthMask(GL_FALSE);
1872 GLboolean depthEnabled;
1873 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1874 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1876 debug_string("disabled depth-buffer writing");
1878 GlobalOpenGL_debugAssertNoErrors();
1881 if (delta & state & RENDER_COLOURWRITE) {
1882 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1883 GlobalOpenGL_debugAssertNoErrors();
1884 } else if (delta & ~state & RENDER_COLOURWRITE) {
1885 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1886 GlobalOpenGL_debugAssertNoErrors();
1889 setState(state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST);
1891 if (delta & state & RENDER_COLOURARRAY) {
1892 glEnableClientState(GL_COLOR_ARRAY);
1893 GlobalOpenGL_debugAssertNoErrors();
1894 debug_colour("enabling color_array");
1895 g_colorArray_enabled = true;
1896 } else if (delta & ~state & RENDER_COLOURARRAY) {
1897 glDisableClientState(GL_COLOR_ARRAY);
1898 glColor4fv(vector4_to_array(self.m_colour));
1899 debug_colour("cleaning color_array");
1900 GlobalOpenGL_debugAssertNoErrors();
1901 g_colorArray_enabled = false;
1904 if (delta & ~state & RENDER_COLOURCHANGE) {
1905 glColor4fv(vector4_to_array(self.m_colour));
1906 GlobalOpenGL_debugAssertNoErrors();
1909 setState(state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE);
1910 setState(state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH);
1912 setState(state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE);
1913 setState(state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH);
1915 setState(state, delta, RENDER_FOG, GL_FOG);
1917 if ((state & RENDER_FOG) != 0) {
1918 setFogState(self.m_fog);
1919 GlobalOpenGL_debugAssertNoErrors();
1920 current.m_fog = self.m_fog;
1923 if (state & RENDER_DEPTHTEST && self.m_depthfunc != current.m_depthfunc) {
1924 glDepthFunc(self.m_depthfunc);
1925 GlobalOpenGL_debugAssertNoErrors();
1926 current.m_depthfunc = self.m_depthfunc;
1929 if (state & RENDER_LINESTIPPLE
1930 && (self.m_linestipple_factor != current.m_linestipple_factor
1931 || self.m_linestipple_pattern != current.m_linestipple_pattern)) {
1932 glLineStipple(self.m_linestipple_factor, self.m_linestipple_pattern);
1933 GlobalOpenGL_debugAssertNoErrors();
1934 current.m_linestipple_factor = self.m_linestipple_factor;
1935 current.m_linestipple_pattern = self.m_linestipple_pattern;
1939 if (state & RENDER_ALPHATEST
1940 && (self.m_alphafunc != current.m_alphafunc
1941 || self.m_alpharef != current.m_alpharef)) {
1942 glAlphaFunc(self.m_alphafunc, self.m_alpharef);
1943 GlobalOpenGL_debugAssertNoErrors();
1944 current.m_alphafunc = self.m_alphafunc;
1945 current.m_alpharef = self.m_alpharef;
1957 //if(state & RENDER_TEXTURE) != 0)
1959 texture0 = self.m_texture;
1960 texture1 = self.m_texture1;
1961 texture2 = self.m_texture2;
1962 texture3 = self.m_texture3;
1963 texture4 = self.m_texture4;
1964 texture5 = self.m_texture5;
1965 texture6 = self.m_texture6;
1966 texture7 = self.m_texture7;
1969 if (GlobalOpenGL().GL_1_3()) {
1970 setTextureState(current.m_texture, texture0, GL_TEXTURE0);
1971 setTextureState(current.m_texture1, texture1, GL_TEXTURE1);
1972 setTextureState(current.m_texture2, texture2, GL_TEXTURE2);
1973 setTextureState(current.m_texture3, texture3, GL_TEXTURE3);
1974 setTextureState(current.m_texture4, texture4, GL_TEXTURE4);
1975 setTextureState(current.m_texture5, texture5, GL_TEXTURE5);
1976 setTextureState(current.m_texture6, texture6, GL_TEXTURE6);
1977 setTextureState(current.m_texture7, texture7, GL_TEXTURE7);
1979 setTextureState(current.m_texture, texture0);
1984 if (state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3]) {
1985 debug_colour("setting alpha");
1986 glColor4f(1, 1, 1, self.m_colour[3]);
1987 GlobalOpenGL_debugAssertNoErrors();
1990 if (!(state & RENDER_TEXTURE)
1991 && (self.m_colour[0] != current.m_colour[0]
1992 || self.m_colour[1] != current.m_colour[1]
1993 || self.m_colour[2] != current.m_colour[2]
1994 || self.m_colour[3] != current.m_colour[3])) {
1995 glColor4fv(vector4_to_array(self.m_colour));
1996 debug_colour("setting non-texture");
1997 GlobalOpenGL_debugAssertNoErrors();
1999 current.m_colour = self.m_colour;
2001 if (state & RENDER_BLEND
2002 && (self.m_blend_src != current.m_blend_src || self.m_blend_dst != current.m_blend_dst)) {
2003 glBlendFunc(self.m_blend_src, self.m_blend_dst);
2004 GlobalOpenGL_debugAssertNoErrors();
2005 current.m_blend_src = self.m_blend_src;
2006 current.m_blend_dst = self.m_blend_dst;
2009 if (!(state & RENDER_FILL)
2010 && self.m_linewidth != current.m_linewidth) {
2011 glLineWidth(self.m_linewidth);
2012 GlobalOpenGL_debugAssertNoErrors();
2013 current.m_linewidth = self.m_linewidth;
2016 if (!(state & RENDER_FILL)
2017 && self.m_pointsize != current.m_pointsize) {
2018 glPointSize(self.m_pointsize);
2019 GlobalOpenGL_debugAssertNoErrors();
2020 current.m_pointsize = self.m_pointsize;
2023 current.m_state = state;
2025 GlobalOpenGL_debugAssertNoErrors();
2028 void Renderables_flush(OpenGLStateBucket::Renderables &renderables, OpenGLState ¤t, unsigned int globalstate,
2029 const Vector3 &viewer)
2031 const Matrix4 *transform = 0;
2033 for (OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i) {
2034 //qglLoadMatrixf(i->m_transform);
2035 if (!transform || (transform != (*i).m_transform && !matrix4_affine_equal(*transform, *(*i).m_transform))) {
2037 transform = (*i).m_transform;
2040 glMultMatrixf(reinterpret_cast<const float *>( transform ));
2042 ((current.m_state & RENDER_CULLFACE) != 0 && matrix4_handedness(*transform) == MATRIX4_RIGHTHANDED)
2048 if (current.m_program != 0 && (*i).m_light != 0) {
2049 const IShader &lightShader = static_cast<OpenGLShader *>((*i).m_light->getShader())->getShader();
2050 if (lightShader.firstLayer() != 0) {
2051 GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
2052 GLuint attenuation_z = lightShader.lightFalloffImage() != 0
2053 ? lightShader.lightFalloffImage()->texture_number
2054 : static_cast<OpenGLShader *>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
2056 setTextureState(current.m_texture3, attenuation_xy, GL_TEXTURE3);
2057 glActiveTexture(GL_TEXTURE3);
2058 glBindTexture(GL_TEXTURE_2D, attenuation_xy);
2059 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
2060 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
2062 setTextureState(current.m_texture4, attenuation_z, GL_TEXTURE4);
2063 glActiveTexture(GL_TEXTURE4);
2064 glBindTexture(GL_TEXTURE_2D, attenuation_z);
2065 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
2066 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2069 AABB lightBounds((*i).m_light->aabb());
2071 Matrix4 world2light(g_matrix4_identity);
2073 if ((*i).m_light->isProjected()) {
2074 world2light = (*i).m_light->projection();
2075 matrix4_multiply_by_matrix4(world2light, matrix4_transposed((*i).m_light->rotation()));
2076 matrix4_translate_by_vec3(world2light, vector3_negated(lightBounds.origin)); // world->lightBounds
2078 if (!(*i).m_light->isProjected()) {
2079 matrix4_translate_by_vec3(world2light, Vector3(0.5f, 0.5f, 0.5f));
2080 matrix4_scale_by_vec3(world2light, Vector3(0.5f, 0.5f, 0.5f));
2081 matrix4_scale_by_vec3(world2light,
2082 Vector3(1.0f / lightBounds.extents.x(), 1.0f / lightBounds.extents.y(),
2083 1.0f / lightBounds.extents.z()));
2084 matrix4_multiply_by_matrix4(world2light, matrix4_transposed((*i).m_light->rotation()));
2085 matrix4_translate_by_vec3(world2light, vector3_negated(lightBounds.origin)); // world->lightBounds
2088 current.m_program->setParameters(viewer, *(*i).m_transform, lightBounds.origin + (*i).m_light->offset(),
2089 (*i).m_light->colour(), world2light);
2090 debug_string("set lightBounds parameters");
2094 (*i).m_renderable->render(current.m_state);
2097 renderables.clear();
2100 void OpenGLStateBucket::render(OpenGLState ¤t, unsigned int globalstate, const Vector3 &viewer)
2102 if ((globalstate & m_state.m_state & RENDER_SCREEN) != 0) {
2103 OpenGLState_apply(m_state, current, globalstate);
2104 debug_colour("screen fill");
2106 glMatrixMode(GL_PROJECTION);
2108 glLoadMatrixf(reinterpret_cast<const float *>( &g_matrix4_identity ));
2110 glMatrixMode(GL_MODELVIEW);
2112 glLoadMatrixf(reinterpret_cast<const float *>( &g_matrix4_identity ));
2115 glVertex3f(-1, -1, 0);
2116 glVertex3f(1, -1, 0);
2117 glVertex3f(1, 1, 0);
2118 glVertex3f(-1, 1, 0);
2121 glMatrixMode(GL_PROJECTION);
2124 glMatrixMode(GL_MODELVIEW);
2126 } else if (!m_renderables.empty()) {
2127 OpenGLState_apply(m_state, current, globalstate);
2128 Renderables_flush(m_renderables, current, globalstate, viewer);
2133 class OpenGLStateMap : public OpenGLStateLibrary {
2134 typedef std::map<CopiedString, OpenGLState> States;
2139 ASSERT_MESSAGE(m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty");
2142 typedef States::iterator iterator;
2146 return m_states.begin();
2151 return m_states.end();
2154 void getDefaultState(OpenGLState &state) const
2156 OpenGLState_constructDefault(state);
2159 void insert(const char *name, const OpenGLState &state)
2161 bool inserted = m_states.insert(States::value_type(name, state)).second;
2162 ASSERT_MESSAGE(inserted, "OpenGLStateMap::insert: " << name << " already exists");
2165 void erase(const char *name)
2167 std::size_t count = m_states.erase(name);
2168 ASSERT_MESSAGE(count == 1, "OpenGLStateMap::erase: " << name << " does not exist");
2171 iterator find(const char *name)
2173 return m_states.find(name);
2177 OpenGLStateMap *g_openglStates = 0;
2179 inline GLenum convertBlendFactor(BlendFactor factor)
2186 case BLEND_SRC_COLOUR:
2187 return GL_SRC_COLOR;
2188 case BLEND_ONE_MINUS_SRC_COLOUR:
2189 return GL_ONE_MINUS_SRC_COLOR;
2190 case BLEND_SRC_ALPHA:
2191 return GL_SRC_ALPHA;
2192 case BLEND_ONE_MINUS_SRC_ALPHA:
2193 return GL_ONE_MINUS_SRC_ALPHA;
2194 case BLEND_DST_COLOUR:
2195 return GL_DST_COLOR;
2196 case BLEND_ONE_MINUS_DST_COLOUR:
2197 return GL_ONE_MINUS_DST_COLOR;
2198 case BLEND_DST_ALPHA:
2199 return GL_DST_ALPHA;
2200 case BLEND_ONE_MINUS_DST_ALPHA:
2201 return GL_ONE_MINUS_DST_ALPHA;
2202 case BLEND_SRC_ALPHA_SATURATE:
2203 return GL_SRC_ALPHA_SATURATE;
2208 /// \todo Define special-case shaders in a data file.
2209 void OpenGLShader::construct(const char *name)
2211 OpenGLState &state = appendDefaultPass();
2214 sscanf(name, "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
2215 state.m_colour[3] = 1.0f;
2216 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE |
2218 state.m_sort = OpenGLState::eSortFullbright;
2222 sscanf(name, "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
2223 state.m_colour[3] = 0.5f;
2224 state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE |
2225 RENDER_DEPTHWRITE | RENDER_BLEND;
2226 state.m_sort = OpenGLState::eSortTranslucent;
2230 sscanf(name, "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
2231 state.m_colour[3] = 1;
2232 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2233 state.m_sort = OpenGLState::eSortFullbright;
2234 state.m_depthfunc = GL_LESS;
2235 state.m_linewidth = 1;
2236 state.m_pointsize = 1;
2240 OpenGLStateMap::iterator i = g_openglStates->find(name);
2241 if (i != g_openglStates->end()) {
2242 state = (*i).second;
2246 if (string_equal(name + 1, "POINT")) {
2247 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2248 state.m_sort = OpenGLState::eSortControlFirst;
2249 state.m_pointsize = 4;
2250 } else if (string_equal(name + 1, "SELPOINT")) {
2251 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2252 state.m_sort = OpenGLState::eSortControlFirst + 1;
2253 state.m_pointsize = 4;
2254 } else if (string_equal(name + 1, "BIGPOINT")) {
2255 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2256 state.m_sort = OpenGLState::eSortControlFirst;
2257 state.m_pointsize = 6;
2258 } else if (string_equal(name + 1, "PIVOT")) {
2259 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
2260 state.m_sort = OpenGLState::eSortGUI1;
2261 state.m_linewidth = 2;
2262 state.m_depthfunc = GL_LEQUAL;
2264 OpenGLState &hiddenLine = appendDefaultPass();
2265 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
2266 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2267 hiddenLine.m_linewidth = 2;
2268 hiddenLine.m_depthfunc = GL_GREATER;
2269 } else if (string_equal(name + 1, "LATTICE")) {
2270 state.m_colour[0] = 1;
2271 state.m_colour[1] = 0.5;
2272 state.m_colour[2] = 0;
2273 state.m_colour[3] = 1;
2274 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2275 state.m_sort = OpenGLState::eSortControlFirst;
2276 } else if (string_equal(name + 1, "WIREFRAME")) {
2277 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2278 state.m_sort = OpenGLState::eSortFullbright;
2279 } else if (string_equal(name + 1, "CAM_HIGHLIGHT")) {
2280 state.m_colour[0] = 1;
2281 state.m_colour[1] = 0;
2282 state.m_colour[2] = 0;
2283 state.m_colour[3] = 0.3f;
2284 state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_BLEND | RENDER_COLOURWRITE |
2286 state.m_sort = OpenGLState::eSortHighlight;
2287 state.m_depthfunc = GL_LEQUAL;
2288 } else if (string_equal(name + 1, "CAM_OVERLAY")) {
2290 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2291 state.m_sort = OpenGLState::eSortOverlayFirst;
2294 RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2295 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2296 state.m_depthfunc = GL_LEQUAL;
2298 OpenGLState &hiddenLine = appendDefaultPass();
2299 hiddenLine.m_colour[0] = 0.75;
2300 hiddenLine.m_colour[1] = 0.75;
2301 hiddenLine.m_colour[2] = 0.75;
2302 hiddenLine.m_colour[3] = 1;
2303 hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE |
2305 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2306 hiddenLine.m_depthfunc = GL_GREATER;
2307 hiddenLine.m_linestipple_factor = 2;
2309 } else if (string_equal(name + 1, "XY_OVERLAY")) {
2310 state.m_colour[0] = g_xywindow_globals.color_selbrushes[0];
2311 state.m_colour[1] = g_xywindow_globals.color_selbrushes[1];
2312 state.m_colour[2] = g_xywindow_globals.color_selbrushes[2];
2313 state.m_colour[3] = 1;
2314 state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
2315 state.m_sort = OpenGLState::eSortOverlayFirst;
2316 state.m_linewidth = 2;
2317 state.m_linestipple_factor = 3;
2318 } else if (string_equal(name + 1, "DEBUG_CLIPPED")) {
2319 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2320 state.m_sort = OpenGLState::eSortLast;
2321 } else if (string_equal(name + 1, "POINTFILE")) {
2322 state.m_colour[0] = 1;
2323 state.m_colour[1] = 0;
2324 state.m_colour[2] = 0;
2325 state.m_colour[3] = 1;
2326 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2327 state.m_sort = OpenGLState::eSortFullbright;
2328 state.m_linewidth = 4;
2329 } else if (string_equal(name + 1, "LIGHT_SPHERE")) {
2330 state.m_colour[0] = .15f * .95f;
2331 state.m_colour[1] = .15f * .95f;
2332 state.m_colour[2] = .15f * .95f;
2333 state.m_colour[3] = 1;
2334 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL | RENDER_COLOURWRITE |
2336 state.m_blend_src = GL_ONE;
2337 state.m_blend_dst = GL_ONE;
2338 state.m_sort = OpenGLState::eSortTranslucent;
2339 } else if (string_equal(name + 1, "Q3MAP2_LIGHT_SPHERE")) {
2340 state.m_colour[0] = .05f;
2341 state.m_colour[1] = .05f;
2342 state.m_colour[2] = .05f;
2343 state.m_colour[3] = 1;
2344 state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
2345 state.m_blend_src = GL_ONE;
2346 state.m_blend_dst = GL_ONE;
2347 state.m_sort = OpenGLState::eSortTranslucent;
2348 } else if (string_equal(name + 1, "WIRE_OVERLAY")) {
2350 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2351 state.m_sort = OpenGLState::eSortOverlayFirst;
2353 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST |
2355 state.m_sort = OpenGLState::eSortGUI1;
2356 state.m_depthfunc = GL_LEQUAL;
2358 OpenGLState &hiddenLine = appendDefaultPass();
2359 hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST |
2360 RENDER_OVERRIDE | RENDER_LINESTIPPLE;
2361 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2362 hiddenLine.m_depthfunc = GL_GREATER;
2364 } else if (string_equal(name + 1, "FLATSHADE_OVERLAY")) {
2365 state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY |
2366 RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST |
2368 state.m_sort = OpenGLState::eSortGUI1;
2369 state.m_depthfunc = GL_LEQUAL;
2371 OpenGLState &hiddenLine = appendDefaultPass();
2372 hiddenLine.m_state =
2373 RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY |
2374 RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE |
2375 RENDER_POLYGONSTIPPLE;
2376 hiddenLine.m_sort = OpenGLState::eSortGUI0;
2377 hiddenLine.m_depthfunc = GL_GREATER;
2378 } else if (string_equal(name + 1, "CLIPPER_OVERLAY")) {
2379 state.m_colour[0] = g_xywindow_globals.color_clipper[0];
2380 state.m_colour[1] = g_xywindow_globals.color_clipper[1];
2381 state.m_colour[2] = g_xywindow_globals.color_clipper[2];
2382 state.m_colour[3] = 1;
2384 RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL | RENDER_POLYGONSTIPPLE;
2385 state.m_sort = OpenGLState::eSortOverlayFirst;
2386 } else if (string_equal(name + 1, "OVERBRIGHT")) {
2387 const float lightScale = 2;
2388 state.m_colour[0] = lightScale * 0.5f;
2389 state.m_colour[1] = lightScale * 0.5f;
2390 state.m_colour[2] = lightScale * 0.5f;
2391 state.m_colour[3] = 0.5;
2392 state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_SCREEN;
2393 state.m_sort = OpenGLState::eSortOverbrighten;
2394 state.m_blend_src = GL_DST_COLOR;
2395 state.m_blend_dst = GL_SRC_COLOR;
2397 // default to something recognisable.. =)
2398 ERROR_MESSAGE("hardcoded renderstate not found");
2399 state.m_colour[0] = 1;
2400 state.m_colour[1] = 0;
2401 state.m_colour[2] = 1;
2402 state.m_colour[3] = 1;
2403 state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2404 state.m_sort = OpenGLState::eSortFirst;
2408 // construction from IShader
2409 m_shader = QERApp_Shader_ForName(name);
2411 if (g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 &&
2412 m_shader->getBump()->texture_number != 0) { // is a bump shader
2413 state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE |
2414 RENDER_COLOURWRITE | RENDER_PROGRAM;
2415 state.m_colour[0] = 0;
2416 state.m_colour[1] = 0;
2417 state.m_colour[2] = 0;
2418 state.m_colour[3] = 1;
2419 state.m_sort = OpenGLState::eSortOpaque;
2421 if (g_ShaderCache->useShaderLanguage()) {
2422 state.m_program = &g_depthFillGLSL;
2424 state.m_program = &g_depthFillARB;
2427 OpenGLState &bumpPass = appendDefaultPass();
2428 bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
2429 bumpPass.m_texture1 = m_shader->getBump()->texture_number;
2430 bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
2433 RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE |
2434 RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2436 if (g_ShaderCache->useShaderLanguage()) {
2437 bumpPass.m_state |= RENDER_LIGHTING;
2438 bumpPass.m_program = &g_bumpGLSL;
2440 bumpPass.m_program = &g_bumpARB;
2443 bumpPass.m_depthfunc = GL_LEQUAL;
2444 bumpPass.m_sort = OpenGLState::eSortMultiFirst;
2445 bumpPass.m_blend_src = GL_ONE;
2446 bumpPass.m_blend_dst = GL_ONE;
2448 state.m_texture = m_shader->getTexture()->texture_number;
2450 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING |
2452 if ((m_shader->getFlags() & QER_CULL) != 0) {
2453 if (m_shader->getCull() == IShader::eCullBack) {
2454 state.m_state |= RENDER_CULLFACE;
2457 state.m_state |= RENDER_CULLFACE;
2459 if ((m_shader->getFlags() & QER_ALPHATEST) != 0) {
2460 state.m_state |= RENDER_ALPHATEST;
2461 IShader::EAlphaFunc alphafunc;
2462 m_shader->getAlphaFunc(&alphafunc, &state.m_alpharef);
2463 switch (alphafunc) {
2464 case IShader::eAlways:
2465 state.m_alphafunc = GL_ALWAYS;
2467 case IShader::eEqual:
2468 state.m_alphafunc = GL_EQUAL;
2470 case IShader::eLess:
2471 state.m_alphafunc = GL_LESS;
2473 case IShader::eGreater:
2474 state.m_alphafunc = GL_GREATER;
2476 case IShader::eLEqual:
2477 state.m_alphafunc = GL_LEQUAL;
2479 case IShader::eGEqual:
2480 state.m_alphafunc = GL_GEQUAL;
2484 reinterpret_cast<Vector3 &>( state.m_colour ) = m_shader->getTexture()->color;
2485 state.m_colour[3] = 1.0f;
2487 if ((m_shader->getFlags() & QER_TRANS) != 0) {
2488 state.m_state |= RENDER_BLEND;
2489 state.m_colour[3] = m_shader->getTrans();
2490 state.m_sort = OpenGLState::eSortTranslucent;
2491 BlendFunc blendFunc = m_shader->getBlendFunc();
2492 state.m_blend_src = convertBlendFactor(blendFunc.m_src);
2493 state.m_blend_dst = convertBlendFactor(blendFunc.m_dst);
2494 if (state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA) {
2495 state.m_state |= RENDER_DEPTHWRITE;
2498 state.m_state |= RENDER_DEPTHWRITE;
2499 state.m_sort = OpenGLState::eSortFullbright;
2506 #include "modulesystem/singletonmodule.h"
2507 #include "modulesystem/moduleregistry.h"
2509 class OpenGLStateLibraryAPI {
2510 OpenGLStateMap m_stateMap;
2512 typedef OpenGLStateLibrary Type;
2514 STRING_CONSTANT(Name, "*");
2516 OpenGLStateLibraryAPI()
2518 g_openglStates = &m_stateMap;
2521 ~OpenGLStateLibraryAPI()
2526 OpenGLStateLibrary *getTable()
2532 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2533 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2534 StaticRegisterModule staticRegisterOpenGLStateLibrary(StaticOpenGLStateLibraryModule::instance());
2536 class ShaderCacheDependencies
2537 : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef {
2539 ShaderCacheDependencies() :
2540 GlobalShadersModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("shaders"))
2545 class ShaderCacheAPI {
2546 ShaderCache *m_shaderCache;
2548 typedef ShaderCache Type;
2550 STRING_CONSTANT(Name, "*");
2554 ShaderCache_Construct();
2556 m_shaderCache = GetShaderCache();
2561 ShaderCache_Destroy();
2564 ShaderCache *getTable()
2566 return m_shaderCache;
2570 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2571 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2572 StaticRegisterModule staticRegisterShaderCache(StaticShaderCacheModule::instance());