1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 #include "renderstate.h"
23
24 #include "debugging/debugging.h"
25 #include "warnings.h"
26
27 #include "ishaders.h"
28 #include "irender.h"
29 #include "itextures.h"
30 #include "igl.h"
31 #include "iglrender.h"
32 #include "renderable.h"
33 #include "qerplugin.h"
34
35 #include <set>
36 #include <vector>
37 #include <list>
38 #include <map>
39
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"
51 #include "os/file.h"
52 #include "preferences.h"
53
54 #include "xywindow.h"
55
56
57
58 #define DEBUG_RENDER 0
59
debug_string(const char * string)60 inline void debug_string( const char* string ){
61 #if (DEBUG_RENDER)
62 globalOutputStream() << string << "\n";
63 #endif
64 }
65
debug_int(const char * comment,int i)66 inline void debug_int( const char* comment, int i ){
67 #if (DEBUG_RENDER)
68 globalOutputStream() << comment << " " << i << "\n";
69 #endif
70 }
71
debug_colour(const char * comment)72 inline void debug_colour( const char* comment ){
73 #if ( DEBUG_RENDER )
74 Vector4 v;
75 glGetFloatv( GL_CURRENT_COLOR, reinterpret_cast<float*>( &v ) );
76 globalOutputStream() << comment << " colour: "
77 << v[0] << " "
78 << v[1] << " "
79 << v[2] << " "
80 << v[3];
81 if ( glIsEnabled( GL_COLOR_ARRAY ) ) {
82 globalOutputStream() << " ARRAY";
83 }
84 if ( glIsEnabled( GL_COLOR_MATERIAL ) ) {
85 globalOutputStream() << " MATERIAL";
86 }
87 globalOutputStream() << "\n";
88 #endif
89 }
90
91 #include "timer.h"
92
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;
97 Timer g_timer;
98
count_prim()99 inline void count_prim(){
100 ++g_count_prims;
101 }
102
count_state()103 inline void count_state(){
104 ++g_count_states;
105 }
106
count_transform()107 inline void count_transform(){
108 ++g_count_transforms;
109 }
110
Renderer_ResetStats()111 void Renderer_ResetStats(){
112 g_count_prims = 0;
113 g_count_states = 0;
114 g_count_transforms = 0;
115 g_timer.start();
116 }
117
Renderer_GetStats()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();
125 }
126
127
printShaderLog(GLhandleARB object)128 void printShaderLog( GLhandleARB object ){
129 GLint log_length = 0;
130 glGetObjectParameterivARB( object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length );
131
132 Array<char> log( log_length );
133 glGetInfoLogARB( object, log_length, &log_length, log.data() );
134
135 globalErrorStream() << StringRange( log.begin(), log.begin() + log_length ) << "\n";
136 }
137
createShader(GLhandleARB program,const char * filename,GLenum type)138 void createShader( GLhandleARB program, const char* filename, GLenum type ){
139 GLhandleARB shader = glCreateShaderObjectARB( type );
140 GlobalOpenGL_debugAssertNoErrors();
141
142 // load shader
143 {
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 );
149
150 const GLcharARB* string = buffer.data();
151 GLint length = GLint( size );
152 glShaderSourceARB( shader, 1, &string, &length );
153 }
154
155 // compile shader
156 {
157 glCompileShaderARB( shader );
158
159 GLint compiled = 0;
160 glGetObjectParameterivARB( shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled );
161
162 if ( !compiled ) {
163 printShaderLog( shader );
164 }
165
166 ASSERT_MESSAGE( compiled, "shader compile failed: " << makeQuoted( filename ) );
167 }
168
169 // attach shader
170 glAttachObjectARB( program, shader );
171
172 glDeleteObjectARB( shader );
173
174 GlobalOpenGL_debugAssertNoErrors();
175 }
176
GLSLProgram_link(GLhandleARB program)177 void GLSLProgram_link( GLhandleARB program ){
178 glLinkProgramARB( program );
179
180 GLint linked = false;
181 glGetObjectParameterivARB( program, GL_OBJECT_LINK_STATUS_ARB, &linked );
182
183 if ( !linked ) {
184 printShaderLog( program );
185 }
186
187 ASSERT_MESSAGE( linked, "program link failed" );
188 }
189
GLSLProgram_validate(GLhandleARB program)190 void GLSLProgram_validate( GLhandleARB program ){
191 glValidateProgramARB( program );
192
193 GLint validated = false;
194 glGetObjectParameterivARB( program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated );
195
196 if ( !validated ) {
197 printShaderLog( program );
198 }
199
200 ASSERT_MESSAGE( validated, "program validation failed" );
201 }
202
203 bool g_bumpGLSLPass_enabled = false;
204 bool g_depthfillPass_enabled = false;
205
206 class GLSLBumpProgram : public GLProgram
207 {
208 public:
209 GLhandleARB m_program;
210 qtexture_t* m_light_attenuation_xy;
211 qtexture_t* m_light_attenuation_z;
212 GLint u_view_origin;
213 GLint u_light_origin;
214 GLint u_light_color;
215 GLint u_bump_scale;
216 GLint u_specular_exponent;
217
GLSLBumpProgram()218 GLSLBumpProgram() : m_program( 0 ), m_light_attenuation_xy( 0 ), m_light_attenuation_z( 0 ){
219 }
220
create()221 void create(){
222 // create program
223 m_program = glCreateProgramObjectARB();
224
225 // create shader
226 {
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 );
230 filename.clear();
231 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glsl";
232 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
233 }
234
235 GLSLProgram_link( m_program );
236 GLSLProgram_validate( m_program );
237
238 glUseProgramObjectARB( m_program );
239
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" );
243
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 );
249
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" );
255
256 glUseProgramObjectARB( 0 );
257
258 GlobalOpenGL_debugAssertNoErrors();
259 }
260
destroy()261 void destroy(){
262 glDeleteObjectARB( m_program );
263 m_program = 0;
264 }
265
enable()266 void enable(){
267 glUseProgramObjectARB( m_program );
268
269 glEnableVertexAttribArrayARB( c_attr_TexCoord0 );
270 glEnableVertexAttribArrayARB( c_attr_Tangent );
271 glEnableVertexAttribArrayARB( c_attr_Binormal );
272
273 GlobalOpenGL_debugAssertNoErrors();
274
275 debug_string( "enable bump" );
276 g_bumpGLSLPass_enabled = true;
277 }
278
disable()279 void disable(){
280 glUseProgramObjectARB( 0 );
281
282 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
283 glDisableVertexAttribArrayARB( c_attr_Tangent );
284 glDisableVertexAttribArrayARB( c_attr_Binormal );
285
286 GlobalOpenGL_debugAssertNoErrors();
287
288 debug_string( "disable bump" );
289 g_bumpGLSLPass_enabled = false;
290 }
291
setParameters(const Vector3 & viewer,const Matrix4 & localToWorld,const Vector3 & origin,const Vector3 & colour,const Matrix4 & world2light)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 );
295
296 Vector3 localLight( origin );
297 matrix4_transform_point( world2local, localLight );
298
299 Vector3 localViewer( viewer );
300 matrix4_transform_point( world2local, localViewer );
301
302 Matrix4 local2light( world2light );
303 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
304
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 );
310
311 glActiveTexture( GL_TEXTURE3 );
312 glClientActiveTexture( GL_TEXTURE3 );
313
314 glMatrixMode( GL_TEXTURE );
315 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
316 glMatrixMode( GL_MODELVIEW );
317
318 GlobalOpenGL_debugAssertNoErrors();
319 }
320 };
321
322 GLSLBumpProgram g_bumpGLSL;
323
324
325 class GLSLDepthFillProgram : public GLProgram
326 {
327 public:
328 GLhandleARB m_program;
329
create()330 void create(){
331 // create program
332 m_program = glCreateProgramObjectARB();
333
334 // create shader
335 {
336 StringOutputStream filename( 256 );
337 filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glsl";
338 createShader( m_program, filename.c_str(), GL_VERTEX_SHADER_ARB );
339 filename.clear();
340 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glsl";
341 createShader( m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB );
342 }
343
344 GLSLProgram_link( m_program );
345 GLSLProgram_validate( m_program );
346
347 GlobalOpenGL_debugAssertNoErrors();
348 }
349
destroy()350 void destroy(){
351 glDeleteObjectARB( m_program );
352 m_program = 0;
353 }
enable()354 void enable(){
355 glUseProgramObjectARB( m_program );
356 GlobalOpenGL_debugAssertNoErrors();
357 debug_string( "enable depthfill" );
358 g_depthfillPass_enabled = true;
359 }
disable()360 void disable(){
361 glUseProgramObjectARB( 0 );
362 GlobalOpenGL_debugAssertNoErrors();
363 debug_string( "disable depthfill" );
364 g_depthfillPass_enabled = false;
365 }
setParameters(const Vector3 & viewer,const Matrix4 & localToWorld,const Vector3 & origin,const Vector3 & colour,const Matrix4 & world2light)366 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
367 }
368 };
369
370 GLSLDepthFillProgram g_depthFillGLSL;
371
372
373 // ARB path
374
createProgram(const char * filename,GLenum type)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 );
381
382 glProgramStringARB( type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei( size ), buffer.data() );
383
384 if ( GL_INVALID_OPERATION == glGetError() ) {
385 GLint errPos;
386 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
387 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_ARB );
388
389 globalErrorStream() << reinterpret_cast<const char*>( filename ) << ":" << errPos << "\n" << reinterpret_cast<const char*>( errString );
390
391 ERROR_MESSAGE( "error in gl program" );
392 }
393 }
394
395 class ARBBumpProgram : public GLProgram
396 {
397 public:
398 GLuint m_vertex_program;
399 GLuint m_fragment_program;
400
create()401 void create(){
402 glEnable( GL_VERTEX_PROGRAM_ARB );
403 glEnable( GL_FRAGMENT_PROGRAM_ARB );
404
405 {
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 );
411
412 glGenProgramsARB( 1, &m_fragment_program );
413 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
414 filename.clear();
415 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glp";
416 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
417 }
418
419 glDisable( GL_VERTEX_PROGRAM_ARB );
420 glDisable( GL_FRAGMENT_PROGRAM_ARB );
421
422 GlobalOpenGL_debugAssertNoErrors();
423 }
424
destroy()425 void destroy(){
426 glDeleteProgramsARB( 1, &m_vertex_program );
427 glDeleteProgramsARB( 1, &m_fragment_program );
428 GlobalOpenGL_debugAssertNoErrors();
429 }
430
enable()431 void enable(){
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 );
436
437 glEnableVertexAttribArrayARB( 8 );
438 glEnableVertexAttribArrayARB( 9 );
439 glEnableVertexAttribArrayARB( 10 );
440 glEnableVertexAttribArrayARB( 11 );
441
442 GlobalOpenGL_debugAssertNoErrors();
443 }
444
disable()445 void disable(){
446 glDisable( GL_VERTEX_PROGRAM_ARB );
447 glDisable( GL_FRAGMENT_PROGRAM_ARB );
448
449 glDisableVertexAttribArrayARB( 8 );
450 glDisableVertexAttribArrayARB( 9 );
451 glDisableVertexAttribArrayARB( 10 );
452 glDisableVertexAttribArrayARB( 11 );
453
454 GlobalOpenGL_debugAssertNoErrors();
455 }
456
setParameters(const Vector3 & viewer,const Matrix4 & localToWorld,const Vector3 & origin,const Vector3 & colour,const Matrix4 & world2light)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 );
460
461 Vector3 localLight( origin );
462 matrix4_transform_point( world2local, localLight );
463
464 Vector3 localViewer( viewer );
465 matrix4_transform_point( world2local, localViewer );
466
467 Matrix4 local2light( world2light );
468 matrix4_multiply_by_matrix4( local2light, localToWorld ); // local->world->light
469
470 // view origin
471 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0 );
472
473 // light origin
474 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1 );
475
476 // light colour
477 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0 );
478
479 // bump scale
480 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0 );
481
482 // specular exponent
483 glProgramLocalParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0 );
484
485
486 glActiveTexture( GL_TEXTURE3 );
487 glClientActiveTexture( GL_TEXTURE3 );
488
489 glMatrixMode( GL_TEXTURE );
490 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
491 glMatrixMode( GL_MODELVIEW );
492
493 GlobalOpenGL_debugAssertNoErrors();
494 }
495 };
496
497 class ARBDepthFillProgram : public GLProgram
498 {
499 public:
500 GLuint m_vertex_program;
501 GLuint m_fragment_program;
502
create()503 void create(){
504 glEnable( GL_VERTEX_PROGRAM_ARB );
505 glEnable( GL_FRAGMENT_PROGRAM_ARB );
506
507 {
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 );
513
514 glGenProgramsARB( 1, &m_fragment_program );
515 glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, m_fragment_program );
516 filename.clear();
517 filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glp";
518 createProgram( filename.c_str(), GL_FRAGMENT_PROGRAM_ARB );
519 }
520
521 glDisable( GL_VERTEX_PROGRAM_ARB );
522 glDisable( GL_FRAGMENT_PROGRAM_ARB );
523
524 GlobalOpenGL_debugAssertNoErrors();
525 }
526
destroy()527 void destroy(){
528 glDeleteProgramsARB( 1, &m_vertex_program );
529 glDeleteProgramsARB( 1, &m_fragment_program );
530 GlobalOpenGL_debugAssertNoErrors();
531 }
532
enable()533 void enable(){
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 );
538
539 GlobalOpenGL_debugAssertNoErrors();
540 }
541
disable()542 void disable(){
543 glDisable( GL_VERTEX_PROGRAM_ARB );
544 glDisable( GL_FRAGMENT_PROGRAM_ARB );
545
546 GlobalOpenGL_debugAssertNoErrors();
547 }
548
setParameters(const Vector3 & viewer,const Matrix4 & localToWorld,const Vector3 & origin,const Vector3 & colour,const Matrix4 & world2light)549 void setParameters( const Vector3& viewer, const Matrix4& localToWorld, const Vector3& origin, const Vector3& colour, const Matrix4& world2light ){
550 }
551 };
552
553 ARBBumpProgram g_bumpARB;
554 ARBDepthFillProgram g_depthFillARB;
555
556
557 #if 0
558 // NV20 path (unfinished)
559
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 );
566
567 glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
568
569 if ( GL_INVALID_OPERATION == glGetError() ) {
570 GLint errPos;
571 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
572 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
573
574 globalErrorStream() << filename << ":" << errPos << "\n" << errString;
575
576 ERROR_MESSAGE( "error in gl program" );
577 }
578 }
579
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;
586
587 void createVertexProgram(){
588 {
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 );
594
595 glGenProgramsNV( 1, &m_fragment_program );
596 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
597 filename.clear();
598 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.nv30";
599 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
600 }
601
602 g_cube = GlobalTexturesCache().capture( "generated/cube" );
603 g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
604
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 );
610
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 );
616
617 GlobalOpenGL_debugAssertNoErrors();
618 }
619
620 void destroyVertexProgram(){
621 glDeleteProgramsNV( 1, &m_vertex_program );
622 glDeleteProgramsNV( 1, &m_fragment_program );
623 GlobalOpenGL_debugAssertNoErrors();
624
625 GlobalTexturesCache().release( g_cube );
626 GlobalTexturesCache().release( g_specular_lookup );
627 GlobalTexturesCache().release( g_attenuation_xy );
628 GlobalTexturesCache().release( g_attenuation_z );
629 }
630
631 bool g_vertexProgram_enabled = false;
632
633 void enableVertexProgram(){
634 //set up the register combiners
635 //two general combiners
636 glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
637
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 );
649
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 );
657
658
659
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 );
664
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 );
670
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 );
675
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 );
684
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 );
689
690 GlobalOpenGL_debugAssertNoErrors();
691 g_vertexProgram_enabled = true;
692 }
693
694 void disableVertexProgram(){
695 glDisable( GL_VERTEX_PROGRAM_NV );
696 glDisable( GL_REGISTER_COMBINERS_NV );
697
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 );
706
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 );
711
712 GlobalOpenGL_debugAssertNoErrors();
713 g_vertexProgram_enabled = false;
714 }
715
716 class GLstringNV
717 {
718 public:
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 ) ) ){
722 }
723 };
724
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" );
730
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 ) );
737
738 glActiveTexture( GL_TEXTURE3 );
739 glClientActiveTexture( GL_TEXTURE3 );
740
741 glMatrixMode( GL_TEXTURE );
742 glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
743 glMatrixMode( GL_MODELVIEW );
744
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 );
747
748 // view origin
749 //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
750
751 // light origin
752 glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
753
754 // light colour
755 glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
756
757 // bump scale
758 //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
759
760 // specular exponent
761 //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
762
763 GlobalOpenGL_debugAssertNoErrors();
764 }
765
766 #endif
767
768
769 bool g_vertexArray_enabled = false;
770 bool g_normalArray_enabled = false;
771 bool g_texcoordArray_enabled = false;
772 bool g_colorArray_enabled = false;
773
OpenGLState_less(const OpenGLState & self,const OpenGLState & other)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;
778 }
779 //! Sort by texture handle.
780 if ( self.m_texture != other.m_texture ) {
781 return self.m_texture < other.m_texture;
782 }
783 if ( self.m_texture1 != other.m_texture1 ) {
784 return self.m_texture1 < other.m_texture1;
785 }
786 if ( self.m_texture2 != other.m_texture2 ) {
787 return self.m_texture2 < other.m_texture2;
788 }
789 if ( self.m_texture3 != other.m_texture3 ) {
790 return self.m_texture3 < other.m_texture3;
791 }
792 if ( self.m_texture4 != other.m_texture4 ) {
793 return self.m_texture4 < other.m_texture4;
794 }
795 if ( self.m_texture5 != other.m_texture5 ) {
796 return self.m_texture5 < other.m_texture5;
797 }
798 if ( self.m_texture6 != other.m_texture6 ) {
799 return self.m_texture6 < other.m_texture6;
800 }
801 if ( self.m_texture7 != other.m_texture7 ) {
802 return self.m_texture7 < other.m_texture7;
803 }
804 //! Sort by state bit-vector.
805 if ( self.m_state != other.m_state ) {
806 return self.m_state < other.m_state;
807 }
808 //! Comparing address makes sure states are never equal.
809 return &self < &other;
810 }
811
OpenGLState_constructDefault(OpenGLState & state)812 void OpenGLState_constructDefault( OpenGLState& state ){
813 state.m_state = RENDER_DEFAULT;
814
815 state.m_texture = 0;
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;
823
824 state.m_colour[0] = 1;
825 state.m_colour[1] = 1;
826 state.m_colour[2] = 1;
827 state.m_colour[3] = 1;
828
829 state.m_depthfunc = GL_LESS;
830
831 state.m_blend_src = GL_SRC_ALPHA;
832 state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
833
834 state.m_alphafunc = GL_ALWAYS;
835 state.m_alpharef = 0;
836
837 state.m_linewidth = 1;
838 state.m_pointsize = 1;
839
840 state.m_linestipple_factor = 1;
841 state.m_linestipple_pattern = 0xaaaa;
842
843 state.m_fog = OpenGLFogState();
844 }
845
846
847
848
849 /// \brief A container of Renderable references.
850 /// May contain the same Renderable multiple times, with different transforms.
851 class OpenGLStateBucket
852 {
853 public:
854 struct RenderTransform
855 {
856 const Matrix4* m_transform;
857 const OpenGLRenderable *m_renderable;
858 const RendererLight* m_light;
859
RenderTransformOpenGLStateBucket::RenderTransform860 RenderTransform( const OpenGLRenderable& renderable, const Matrix4& transform, const RendererLight* light )
861 : m_transform( &transform ), m_renderable( &renderable ), m_light( light ){
862 }
863 };
864
865 typedef std::vector<RenderTransform> Renderables;
866
867 private:
868
869 OpenGLState m_state;
870 Renderables m_renderables;
871
872 public:
OpenGLStateBucket()873 OpenGLStateBucket(){
874 }
addRenderable(const OpenGLRenderable & renderable,const Matrix4 & modelview,const RendererLight * light=0)875 void addRenderable( const OpenGLRenderable& renderable, const Matrix4& modelview, const RendererLight* light = 0 ){
876 m_renderables.push_back( RenderTransform( renderable, modelview, light ) );
877 }
878
state()879 OpenGLState& state(){
880 return m_state;
881 }
882
883 void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
884 };
885
886 #define LIGHT_SHADER_DEBUG 0
887
888 #if LIGHT_SHADER_DEBUG
889 typedef std::vector<Shader*> LightDebugShaders;
890 LightDebugShaders g_lightDebugShaders;
891 #endif
892
893 class OpenGLStateLess
894 {
895 public:
operator ()(const OpenGLState & self,const OpenGLState & other) const896 bool operator()( const OpenGLState& self, const OpenGLState& other ) const {
897 return OpenGLState_less( self, other );
898 }
899 };
900
901 typedef ConstReference<OpenGLState> OpenGLStateReference;
902 typedef std::map<OpenGLStateReference, OpenGLStateBucket*, OpenGLStateLess> OpenGLStates;
903 OpenGLStates g_state_sorted;
904
905 class OpenGLStateBucketAdd
906 {
907 OpenGLStateBucket& m_bucket;
908 const OpenGLRenderable& m_renderable;
909 const Matrix4& m_modelview;
910 public:
911 typedef const RendererLight& first_argument_type;
912
OpenGLStateBucketAdd(OpenGLStateBucket & bucket,const OpenGLRenderable & renderable,const Matrix4 & modelview)913 OpenGLStateBucketAdd( OpenGLStateBucket& bucket, const OpenGLRenderable& renderable, const Matrix4& modelview ) :
914 m_bucket( bucket ), m_renderable( renderable ), m_modelview( modelview ){
915 }
operator ()(const RendererLight & light)916 void operator()( const RendererLight& light ){
917 m_bucket.addRenderable( m_renderable, m_modelview, &light );
918 }
919 };
920
921 class CountLights
922 {
923 std::size_t m_count;
924 public:
925 typedef RendererLight& first_argument_type;
926
CountLights()927 CountLights() : m_count( 0 ){
928 }
operator ()(const RendererLight & light)929 void operator()( const RendererLight& light ){
930 ++m_count;
931 }
count() const932 std::size_t count() const {
933 return m_count;
934 }
935 };
936
937 class OpenGLShader : public Shader
938 {
939 typedef std::list<OpenGLStateBucket*> Passes;
940 Passes m_passes;
941 IShader* m_shader;
942 std::size_t m_used;
943 ModuleObservers m_observers;
944 public:
OpenGLShader()945 OpenGLShader() : m_shader( 0 ), m_used( 0 ){
946 }
~OpenGLShader()947 ~OpenGLShader(){
948 }
949 void construct( const char* name );
destroy()950 void destroy(){
951 if ( m_shader ) {
952 m_shader->DecRef();
953 }
954 m_shader = 0;
955
956 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
957 {
958 delete *i;
959 }
960 m_passes.clear();
961 }
addRenderable(const OpenGLRenderable & renderable,const Matrix4 & modelview,const LightList * lights)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 )
964 {
965 #if LIGHT_SHADER_DEBUG
966 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
967 if ( lights != 0 ) {
968 CountLights counter;
969 lights->forEachLight( makeCallback1( counter ) );
970 globalOutputStream() << "count = " << counter.count() << "\n";
971 for ( std::size_t i = 0; i < counter.count(); ++i )
972 {
973 g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
974 }
975 }
976 }
977 else
978 #else
979 if ( ( ( *i )->state().m_state & RENDER_BUMP ) != 0 ) {
980 if ( lights != 0 ) {
981 OpenGLStateBucketAdd add( *( *i ), renderable, modelview );
982 lights->forEachLight( makeCallback1( add ) );
983 }
984 }
985 else
986 #endif
987 {
988 ( *i )->addRenderable( renderable, modelview );
989 }
990 }
991 }
incrementUsed()992 void incrementUsed(){
993 if ( ++m_used == 1 && m_shader != 0 ) {
994 m_shader->SetInUse( true );
995 }
996 }
decrementUsed()997 void decrementUsed(){
998 if ( --m_used == 0 && m_shader != 0 ) {
999 m_shader->SetInUse( false );
1000 }
1001 }
realised() const1002 bool realised() const {
1003 return m_shader != 0;
1004 }
attach(ModuleObserver & observer)1005 void attach( ModuleObserver& observer ){
1006 if ( realised() ) {
1007 observer.realise();
1008 }
1009 m_observers.attach( observer );
1010 }
detach(ModuleObserver & observer)1011 void detach( ModuleObserver& observer ){
1012 if ( realised() ) {
1013 observer.unrealise();
1014 }
1015 m_observers.detach( observer );
1016 }
realise(const CopiedString & name)1017 void realise( const CopiedString& name ){
1018 construct( name.c_str() );
1019
1020 if ( m_used != 0 && m_shader != 0 ) {
1021 m_shader->SetInUse( true );
1022 }
1023
1024 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1025 {
1026 g_state_sorted.insert( OpenGLStates::value_type( OpenGLStateReference( ( *i )->state() ), *i ) );
1027 }
1028
1029 m_observers.realise();
1030 }
unrealise()1031 void unrealise(){
1032 m_observers.unrealise();
1033
1034 for ( Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i )
1035 {
1036 g_state_sorted.erase( OpenGLStateReference( ( *i )->state() ) );
1037 }
1038
1039 destroy();
1040 }
getTexture() const1041 qtexture_t& getTexture() const {
1042 ASSERT_NOTNULL( m_shader );
1043 return *m_shader->getTexture();
1044 }
getFlags() const1045 unsigned int getFlags() const {
1046 ASSERT_NOTNULL( m_shader );
1047 return m_shader->getFlags();
1048 }
getShader() const1049 IShader& getShader() const {
1050 ASSERT_NOTNULL( m_shader );
1051 return *m_shader;
1052 }
appendDefaultPass()1053 OpenGLState& appendDefaultPass(){
1054 m_passes.push_back( new OpenGLStateBucket );
1055 OpenGLState& state = m_passes.back()->state();
1056 OpenGLState_constructDefault( state );
1057 return state;
1058 }
1059 };
1060
1061
lightEnabled(const RendererLight & light,const LightCullable & cullable)1062 inline bool lightEnabled( const RendererLight& light, const LightCullable& cullable ){
1063 return cullable.testLight( light );
1064 }
1065
1066 typedef std::set<RendererLight*> RendererLights;
1067
1068 #define DEBUG_LIGHT_SYNC 0
1069
1070 class LinearLightList : public LightList
1071 {
1072 LightCullable& m_cullable;
1073 RendererLights& m_allLights;
1074 Callback m_evaluateChanged;
1075
1076 typedef std::list<RendererLight*> Lights;
1077 mutable Lights m_lights;
1078 mutable bool m_lightsChanged;
1079 public:
LinearLightList(LightCullable & cullable,RendererLights & lights,const Callback & evaluateChanged)1080 LinearLightList( LightCullable& cullable, RendererLights& lights, const Callback& evaluateChanged ) :
1081 m_cullable( cullable ), m_allLights( lights ), m_evaluateChanged( evaluateChanged ){
1082 m_lightsChanged = true;
1083 }
evaluateLights() const1084 void evaluateLights() const {
1085 m_evaluateChanged();
1086 if ( m_lightsChanged ) {
1087 m_lightsChanged = false;
1088
1089 m_lights.clear();
1090 m_cullable.clearLights();
1091 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1092 {
1093 if ( lightEnabled( *( *i ), m_cullable ) ) {
1094 m_lights.push_back( *i );
1095 m_cullable.insertLight( *( *i ) );
1096 }
1097 }
1098 }
1099 #if ( DEBUG_LIGHT_SYNC )
1100 else
1101 {
1102 Lights lights;
1103 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1104 {
1105 if ( lightEnabled( *( *i ), m_cullable ) ) {
1106 lights.push_back( *i );
1107 }
1108 }
1109 ASSERT_MESSAGE(
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"
1113 );
1114 }
1115 #endif
1116 }
forEachLight(const RendererLightCallback & callback) const1117 void forEachLight( const RendererLightCallback& callback ) const {
1118 evaluateLights();
1119
1120 for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i )
1121 {
1122 callback( *( *i ) );
1123 }
1124 }
lightsChanged() const1125 void lightsChanged() const {
1126 m_lightsChanged = true;
1127 }
1128 };
1129
setFogState(const OpenGLFogState & state)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 ) );
1137 }
1138
1139 #define DEBUG_SHADERS 0
1140
1141 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver
1142 {
1143 class CreateOpenGLShader
1144 {
1145 OpenGLShaderCache* m_cache;
1146 public:
CreateOpenGLShader(OpenGLShaderCache * cache=0)1147 explicit CreateOpenGLShader( OpenGLShaderCache* cache = 0 )
1148 : m_cache( cache ){
1149 }
construct(const CopiedString & name)1150 OpenGLShader* construct( const CopiedString& name ){
1151 OpenGLShader* shader = new OpenGLShader;
1152 if ( m_cache->realised() ) {
1153 shader->realise( name );
1154 }
1155 return shader;
1156 }
destroy(OpenGLShader * shader)1157 void destroy( OpenGLShader* shader ){
1158 if ( m_cache->realised() ) {
1159 shader->unrealise();
1160 }
1161 delete shader;
1162 }
1163 };
1164
1165 typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1166 Shaders m_shaders;
1167 std::size_t m_unrealised;
1168
1169 bool m_lightingEnabled;
1170 bool m_lightingSupported;
1171 bool m_useShaderLanguage;
1172
1173 public:
OpenGLShaderCache()1174 OpenGLShaderCache()
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 ){
1182 }
~OpenGLShaderCache()1183 ~OpenGLShaderCache(){
1184 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1185 {
1186 globalOutputStream() << "leaked shader: " << makeQuoted( ( *i ).key.c_str() ) << "\n";
1187 }
1188 }
capture(const char * name)1189 Shader* capture( const char* name ){
1190 ASSERT_MESSAGE( name[0] == '$'
1191 || *name == '['
1192 || *name == '<'
1193 || *name == '('
1194 || strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
1195 #if DEBUG_SHADERS
1196 globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1197 #endif
1198 return m_shaders.capture( name ).get();
1199 }
release(const char * name)1200 void release( const char *name ){
1201 #if DEBUG_SHADERS
1202 globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1203 #endif
1204 m_shaders.release( name );
1205 }
render(RenderStateFlags globalstate,const Matrix4 & modelview,const Matrix4 & projection,const Vector3 & viewer)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 ) );
1209 #if 0
1210 //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1211 #endif
1212
1213 glMatrixMode( GL_MODELVIEW );
1214 glLoadMatrixf( reinterpret_cast<const float*>( &modelview ) );
1215 #if 0
1216 //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1217 #endif
1218
1219 ASSERT_MESSAGE( realised(), "render states are not realised" );
1220
1221 // global settings that are not set in renderstates
1222 glFrontFace( GL_CW );
1223 glCullFace( GL_BACK );
1224 glPolygonOffset( -1, 1 );
1225 {
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
1243 };
1244 glPolygonStipple( pattern );
1245 }
1246 glEnableClientState( GL_VERTEX_ARRAY );
1247 g_vertexArray_enabled = true;
1248 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1249
1250 if ( GlobalOpenGL().GL_1_3() ) {
1251 glActiveTexture( GL_TEXTURE0 );
1252 glClientActiveTexture( GL_TEXTURE0 );
1253 }
1254
1255 if ( GlobalOpenGL().ARB_shader_objects() ) {
1256 glUseProgramObjectARB( 0 );
1257 glDisableVertexAttribArrayARB( c_attr_TexCoord0 );
1258 glDisableVertexAttribArrayARB( c_attr_Tangent );
1259 glDisableVertexAttribArrayARB( c_attr_Binormal );
1260 }
1261
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 );
1265 }
1266
1267 OpenGLState current;
1268 OpenGLState_constructDefault( current );
1269 current.m_sort = OpenGLState::eSortFirst;
1270
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 );
1293
1294 glBindTexture( GL_TEXTURE_2D, 0 );
1295 glColor4f( 1,1,1,1 );
1296 glDepthFunc( GL_LESS );
1297 glAlphaFunc( GL_ALWAYS, 0 );
1298 glLineWidth( 1 );
1299 glPointSize( 1 );
1300
1301 glHint( GL_FOG_HINT, GL_NICEST );
1302 glDisable( GL_FOG );
1303 setFogState( OpenGLFogState() );
1304
1305 GlobalOpenGL_debugAssertNoErrors();
1306
1307 debug_string( "begin rendering" );
1308 for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
1309 {
1310 ( *i ).second->render( current, globalstate, viewer );
1311 }
1312 debug_string( "end rendering" );
1313 }
realise()1314 void realise(){
1315 if ( --m_unrealised == 0 ) {
1316 if ( lightingSupported() && lightingEnabled() ) {
1317 if ( useShaderLanguage() ) {
1318 g_bumpGLSL.create();
1319 g_depthFillGLSL.create();
1320 }
1321 else
1322 {
1323 g_bumpARB.create();
1324 g_depthFillARB.create();
1325 }
1326 }
1327
1328 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1329 {
1330 if ( !( *i ).value.empty() ) {
1331 ( *i ).value->realise( i->key );
1332 }
1333 }
1334 }
1335 }
unrealise()1336 void unrealise(){
1337 if ( ++m_unrealised == 1 ) {
1338 for ( Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i )
1339 {
1340 if ( !( *i ).value.empty() ) {
1341 ( *i ).value->unrealise();
1342 }
1343 }
1344 if ( GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled() ) {
1345 if ( useShaderLanguage() ) {
1346 g_bumpGLSL.destroy();
1347 g_depthFillGLSL.destroy();
1348 }
1349 else
1350 {
1351 g_bumpARB.destroy();
1352 g_depthFillARB.destroy();
1353 }
1354 }
1355 }
1356 }
realised()1357 bool realised(){
1358 return m_unrealised == 0;
1359 }
1360
1361
lightingEnabled() const1362 bool lightingEnabled() const {
1363 return m_lightingEnabled;
1364 }
lightingSupported() const1365 bool lightingSupported() const {
1366 return m_lightingSupported;
1367 }
useShaderLanguage() const1368 bool useShaderLanguage() const {
1369 return m_useShaderLanguage;
1370 }
setLighting(bool supported,bool enabled)1371 void setLighting( bool supported, bool enabled ){
1372 bool refresh = ( m_lightingSupported && m_lightingEnabled ) != ( supported && enabled );
1373
1374 if ( refresh ) {
1375 unrealise();
1376 GlobalShaderSystem().setLightingEnabled( supported && enabled );
1377 }
1378
1379 m_lightingSupported = supported;
1380 m_lightingEnabled = enabled;
1381
1382 if ( refresh ) {
1383 realise();
1384 }
1385 }
extensionsInitialised()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(),
1394 m_lightingEnabled
1395 );
1396
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";
1401 }
1402 if ( !GlobalOpenGL().ARB_vertex_program() ) {
1403 globalOutputStream() << " GL_ARB_vertex_program\n";
1404 }
1405 if ( !GlobalOpenGL().ARB_fragment_program() ) {
1406 globalOutputStream() << " GL_ARB_fragment_program\n";
1407 }
1408 if ( !GlobalOpenGL().ARB_shader_objects() ) {
1409 globalOutputStream() << " GL_ARB_shader_objects\n";
1410 }
1411 if ( !GlobalOpenGL().ARB_vertex_shader() ) {
1412 globalOutputStream() << " GL_ARB_vertex_shader\n";
1413 }
1414 if ( !GlobalOpenGL().ARB_fragment_shader() ) {
1415 globalOutputStream() << " GL_ARB_fragment_shader\n";
1416 }
1417 if ( !GlobalOpenGL().ARB_shading_language_100() ) {
1418 globalOutputStream() << " GL_ARB_shading_language_100\n";
1419 }
1420 }
1421 }
setLightingEnabled(bool enabled)1422 void setLightingEnabled( bool enabled ){
1423 setLighting( m_lightingSupported, enabled );
1424 }
1425
1426 // light culling
1427
1428 RendererLights m_lights;
1429 bool m_lightsChanged;
1430 typedef std::map<LightCullable*, LinearLightList> LightLists;
1431 LightLists m_lightLists;
1432
attach(LightCullable & cullable)1433 const LightList& attach( LightCullable& cullable ){
1434 return ( *m_lightLists.insert( LightLists::value_type( &cullable, LinearLightList( cullable, m_lights, EvaluateChangedCaller( *this ) ) ) ).first ).second;
1435 }
detach(LightCullable & cullable)1436 void detach( LightCullable& cullable ){
1437 m_lightLists.erase( &cullable );
1438 }
changed(LightCullable & 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();
1443 }
attach(RendererLight & light)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 );
1447 changed( light );
1448 }
detach(RendererLight & 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 );
1452 changed( light );
1453 }
changed(RendererLight & light)1454 void changed( RendererLight& light ){
1455 m_lightsChanged = true;
1456 }
evaluateChanged()1457 void evaluateChanged(){
1458 if ( m_lightsChanged ) {
1459 m_lightsChanged = false;
1460 for ( LightLists::iterator i = m_lightLists.begin(); i != m_lightLists.end(); ++i )
1461 {
1462 ( *i ).second.lightsChanged();
1463 }
1464 }
1465 }
1466 typedef MemberCaller<OpenGLShaderCache, &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1467
1468 typedef std::set<const Renderable*> Renderables;
1469 Renderables m_renderables;
1470 mutable bool m_traverseRenderablesMutex;
1471
1472 // renderables
attachRenderable(const Renderable & renderable)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 );
1477 }
detachRenderable(const Renderable & 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 );
1482 }
forEachRenderable(const RenderableCallback & callback) const1483 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 )
1487 {
1488 callback( *( *i ) );
1489 }
1490 m_traverseRenderablesMutex = false;
1491 }
1492 };
1493
1494 static OpenGLShaderCache* g_ShaderCache;
1495
ShaderCache_extensionsInitialised()1496 void ShaderCache_extensionsInitialised(){
1497 g_ShaderCache->extensionsInitialised();
1498 }
1499
ShaderCache_setBumpEnabled(bool enabled)1500 void ShaderCache_setBumpEnabled( bool enabled ){
1501 g_ShaderCache->setLightingEnabled( enabled );
1502 }
1503
1504
1505 Vector3 g_DebugShaderColours[256];
1506 Shader* g_defaultPointLight = 0;
1507
ShaderCache_Construct()1508 void ShaderCache_Construct(){
1509 g_ShaderCache = new OpenGLShaderCache;
1510 GlobalTexturesCache().attach( *g_ShaderCache );
1511 GlobalShaderSystem().attach( *g_ShaderCache );
1512
1513 if ( g_pGameDescription->mGameType == "doom3" ) {
1514 g_defaultPointLight = g_ShaderCache->capture( "lights/defaultPointLight" );
1515 //Shader* overbright =
1516 g_ShaderCache->capture( "$OVERBRIGHT" );
1517
1518 #if LIGHT_SHADER_DEBUG
1519 for ( std::size_t i = 0; i < 256; ++i )
1520 {
1521 g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1522 }
1523
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 );
1536
1537 g_lightDebugShaders.reserve( 256 );
1538 StringOutputStream buffer( 256 );
1539 for ( std::size_t i = 0; i < 256; ++i )
1540 {
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() ) );
1543 buffer.clear();
1544 }
1545 #endif
1546 }
1547 }
1548
ShaderCache_Destroy()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;
1554
1555 #if LIGHT_SHADER_DEBUG
1556 g_lightDebugShaders.clear();
1557 StringOutputStream buffer( 256 );
1558 for ( std::size_t i = 0; i < 256; ++i )
1559 {
1560 buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1561 g_ShaderCache->release( buffer.c_str() );
1562 }
1563 #endif
1564 }
1565
1566 GlobalShaderSystem().detach( *g_ShaderCache );
1567 GlobalTexturesCache().detach( *g_ShaderCache );
1568 delete g_ShaderCache;
1569 }
1570
GetShaderCache()1571 ShaderCache* GetShaderCache(){
1572 return g_ShaderCache;
1573 }
1574
setTextureState(GLint & current,const GLint & texture,GLenum textureUnit)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();
1581 current = texture;
1582 }
1583 }
1584
setTextureState(GLint & current,const GLint & texture)1585 inline void setTextureState( GLint& current, const GLint& texture ){
1586 if ( texture != current ) {
1587 glBindTexture( GL_TEXTURE_2D, texture );
1588 GlobalOpenGL_debugAssertNoErrors();
1589 current = texture;
1590 }
1591 }
1592
setState(unsigned int state,unsigned int delta,unsigned int flag,GLenum glflag)1593 inline void setState( unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag ){
1594 if ( delta & state & flag ) {
1595 glEnable( glflag );
1596 GlobalOpenGL_debugAssertNoErrors();
1597 }
1598 else if ( delta & ~state & flag ) {
1599 glDisable( glflag );
1600 GlobalOpenGL_debugAssertNoErrors();
1601 }
1602 }
1603
OpenGLState_apply(const OpenGLState & self,OpenGLState & current,unsigned int globalstate)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 ) ) );
1609
1610 count_state();
1611
1612 if ( self.m_state & RENDER_OVERRIDE ) {
1613 globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1614 }
1615
1616 const unsigned int state = self.m_state & globalstate;
1617 const unsigned int delta = state ^ current.m_state;
1618
1619 GlobalOpenGL_debugAssertNoErrors();
1620
1621 GLProgram* program = ( state & RENDER_PROGRAM ) != 0 ? self.m_program : 0;
1622
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" );
1628 }
1629
1630 current.m_program = program;
1631
1632 if ( current.m_program != 0 ) {
1633 current.m_program->enable();
1634 }
1635 }
1636
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();
1642 }
1643 else if ( delta & ~state & RENDER_FILL ) {
1644 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
1645 GlobalOpenGL_debugAssertNoErrors();
1646 }
1647
1648 setState( state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE );
1649
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;
1657 }
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;
1665 }
1666
1667 if ( delta & state & RENDER_TEXTURE ) {
1668 GlobalOpenGL_debugAssertNoErrors();
1669
1670 if ( GlobalOpenGL().GL_1_3() ) {
1671 glActiveTexture( GL_TEXTURE0 );
1672 glClientActiveTexture( GL_TEXTURE0 );
1673 }
1674
1675 glEnable( GL_TEXTURE_2D );
1676
1677 glColor4f( 1,1,1,self.m_colour[3] );
1678 debug_colour( "setting texture" );
1679
1680 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1681 GlobalOpenGL_debugAssertNoErrors();
1682 g_texcoordArray_enabled = true;
1683 }
1684 else if ( delta & ~state & RENDER_TEXTURE ) {
1685 if ( GlobalOpenGL().GL_1_3() ) {
1686 glActiveTexture( GL_TEXTURE0 );
1687 glClientActiveTexture( GL_TEXTURE0 );
1688 }
1689
1690 glDisable( GL_TEXTURE_2D );
1691 glBindTexture( GL_TEXTURE_2D, 0 );
1692 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1693
1694 GlobalOpenGL_debugAssertNoErrors();
1695 g_texcoordArray_enabled = false;
1696 }
1697
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
1704
1705 glEnable( GL_BLEND );
1706 if ( GlobalOpenGL().GL_1_3() ) {
1707 glActiveTexture( GL_TEXTURE0 );
1708 }
1709 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
1710 GlobalOpenGL_debugAssertNoErrors();
1711 }
1712 else if ( delta & ~state & RENDER_BLEND ) {
1713 glDisable( GL_BLEND );
1714 if ( GlobalOpenGL().GL_1_3() ) {
1715 glActiveTexture( GL_TEXTURE0 );
1716 }
1717 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1718 GlobalOpenGL_debugAssertNoErrors();
1719 }
1720
1721 setState( state, delta, RENDER_CULLFACE, GL_CULL_FACE );
1722
1723 if ( delta & state & RENDER_SMOOTH ) {
1724 glShadeModel( GL_SMOOTH );
1725 GlobalOpenGL_debugAssertNoErrors();
1726 }
1727 else if ( delta & ~state & RENDER_SMOOTH ) {
1728 glShadeModel( GL_FLAT );
1729 GlobalOpenGL_debugAssertNoErrors();
1730 }
1731
1732 setState( state, delta, RENDER_SCALED, GL_NORMALIZE ); // not GL_RESCALE_NORMAL
1733
1734 setState( state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST );
1735
1736 if ( delta & state & RENDER_DEPTHWRITE ) {
1737 glDepthMask( GL_TRUE );
1738
1739 #if DEBUG_RENDER
1740 GLboolean depthEnabled;
1741 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1742 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1743 #endif
1744 debug_string( "enabled depth-buffer writing" );
1745
1746 GlobalOpenGL_debugAssertNoErrors();
1747 }
1748 else if ( delta & ~state & RENDER_DEPTHWRITE ) {
1749 glDepthMask( GL_FALSE );
1750
1751 #if DEBUG_RENDER
1752 GLboolean depthEnabled;
1753 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1754 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1755 #endif
1756 debug_string( "disabled depth-buffer writing" );
1757
1758 GlobalOpenGL_debugAssertNoErrors();
1759 }
1760
1761 if ( delta & state & RENDER_COLOURWRITE ) {
1762 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
1763 GlobalOpenGL_debugAssertNoErrors();
1764 }
1765 else if ( delta & ~state & RENDER_COLOURWRITE ) {
1766 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
1767 GlobalOpenGL_debugAssertNoErrors();
1768 }
1769
1770 setState( state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST );
1771
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;
1777 }
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;
1784 }
1785
1786 if ( delta & ~state & RENDER_COLOURCHANGE ) {
1787 glColor4fv( vector4_to_array( self.m_colour ) );
1788 GlobalOpenGL_debugAssertNoErrors();
1789 }
1790
1791 setState( state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE );
1792 setState( state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH );
1793
1794 setState( state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE );
1795 setState( state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH );
1796
1797 setState( state, delta, RENDER_FOG, GL_FOG );
1798
1799 if ( ( state & RENDER_FOG ) != 0 ) {
1800 setFogState( self.m_fog );
1801 GlobalOpenGL_debugAssertNoErrors();
1802 current.m_fog = self.m_fog;
1803 }
1804
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;
1809 }
1810
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;
1818 }
1819
1820
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;
1828 }
1829
1830 {
1831 GLint texture0 = 0;
1832 GLint texture1 = 0;
1833 GLint texture2 = 0;
1834 GLint texture3 = 0;
1835 GLint texture4 = 0;
1836 GLint texture5 = 0;
1837 GLint texture6 = 0;
1838 GLint texture7 = 0;
1839 //if(state & RENDER_TEXTURE) != 0)
1840 {
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;
1849 }
1850
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 );
1860 }
1861 else
1862 {
1863 setTextureState( current.m_texture, texture0 );
1864 }
1865 }
1866
1867
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();
1872 }
1873
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();
1882 }
1883 current.m_colour = self.m_colour;
1884
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;
1891 }
1892
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;
1898 }
1899
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;
1905 }
1906
1907 current.m_state = state;
1908
1909 GlobalOpenGL_debugAssertNoErrors();
1910 }
1911
Renderables_flush(OpenGLStateBucket::Renderables & renderables,OpenGLState & current,unsigned int globalstate,const Vector3 & viewer)1912 void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
1913 const Matrix4* transform = 0;
1914 glPushMatrix();
1915 for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
1916 {
1917 //qglLoadMatrixf(i->m_transform);
1918 if ( !transform || ( transform != ( *i ).m_transform && !matrix4_affine_equal( *transform, *( *i ).m_transform ) ) ) {
1919 count_transform();
1920 transform = ( *i ).m_transform;
1921 glPopMatrix();
1922 glPushMatrix();
1923 glMultMatrixf( reinterpret_cast<const float*>( transform ) );
1924 glFrontFace( ( ( current.m_state & RENDER_CULLFACE ) != 0 && matrix4_handedness( *transform ) == MATRIX4_RIGHTHANDED ) ? GL_CW : GL_CCW );
1925 }
1926
1927 count_prim();
1928
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;
1936
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 );
1942
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 );
1948
1949
1950 AABB lightBounds( ( *i ).m_light->aabb() );
1951
1952 Matrix4 world2light( g_matrix4_identity );
1953
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
1958 }
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
1965 }
1966
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" );
1969 }
1970 }
1971
1972 ( *i ).m_renderable->render( current.m_state );
1973 }
1974 glPopMatrix();
1975 renderables.clear();
1976 }
1977
render(OpenGLState & current,unsigned int globalstate,const Vector3 & viewer)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" );
1982
1983 glMatrixMode( GL_PROJECTION );
1984 glPushMatrix();
1985 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1986
1987 glMatrixMode( GL_MODELVIEW );
1988 glPushMatrix();
1989 glLoadMatrixf( reinterpret_cast<const float*>( &g_matrix4_identity ) );
1990
1991 glBegin( GL_QUADS );
1992 glVertex3f( -1, -1, 0 );
1993 glVertex3f( 1, -1, 0 );
1994 glVertex3f( 1, 1, 0 );
1995 glVertex3f( -1, 1, 0 );
1996 glEnd();
1997
1998 glMatrixMode( GL_PROJECTION );
1999 glPopMatrix();
2000
2001 glMatrixMode( GL_MODELVIEW );
2002 glPopMatrix();
2003 }
2004 else if ( !m_renderables.empty() ) {
2005 OpenGLState_apply( m_state, current, globalstate );
2006 Renderables_flush( m_renderables, current, globalstate, viewer );
2007 }
2008 }
2009
2010
2011 class OpenGLStateMap : public OpenGLStateLibrary
2012 {
2013 typedef std::map<CopiedString, OpenGLState> States;
2014 States m_states;
2015 public:
~OpenGLStateMap()2016 ~OpenGLStateMap(){
2017 ASSERT_MESSAGE( m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty" );
2018 }
2019
2020 typedef States::iterator iterator;
begin()2021 iterator begin(){
2022 return m_states.begin();
2023 }
end()2024 iterator end(){
2025 return m_states.end();
2026 }
2027
getDefaultState(OpenGLState & state) const2028 void getDefaultState( OpenGLState& state ) const {
2029 OpenGLState_constructDefault( state );
2030 }
2031
insert(const char * name,const OpenGLState & 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" );
2035 }
erase(const char * name)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" );
2039 }
2040
find(const char * name)2041 iterator find( const char* name ){
2042 return m_states.find( name );
2043 }
2044 };
2045
2046 OpenGLStateMap* g_openglStates = 0;
2047
convertBlendFactor(BlendFactor factor)2048 inline GLenum convertBlendFactor( BlendFactor factor ){
2049 switch ( factor )
2050 {
2051 case BLEND_ZERO:
2052 return GL_ZERO;
2053 case BLEND_ONE:
2054 return GL_ONE;
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;
2073 }
2074 return GL_ZERO;
2075 }
2076
2077 /// \todo Define special-case shaders in a data file.
construct(const char * name)2078 void OpenGLShader::construct( const char* name ){
2079 OpenGLState& state = appendDefaultPass();
2080 switch ( name[0] )
2081 {
2082 case '(':
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;
2087 break;
2088
2089 case '[':
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;
2094 break;
2095
2096 case '<':
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;
2104 break;
2105
2106 case '$':
2107 {
2108 OpenGLStateMap::iterator i = g_openglStates->find( name );
2109 if ( i != g_openglStates->end() ) {
2110 state = ( *i ).second;
2111 break;
2112 }
2113 }
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;
2118 }
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;
2123 }
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;
2128 }
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;
2134
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;
2140 }
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;
2148 }
2149 else if ( string_equal( name + 1, "WIREFRAME" ) ) {
2150 state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2151 state.m_sort = OpenGLState::eSortFullbright;
2152 }
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;
2161 }
2162 else if ( string_equal( name + 1, "CAM_OVERLAY" ) ) {
2163 #if 0
2164 state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2165 state.m_sort = OpenGLState::eSortOverlayFirst;
2166 #else
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;
2170
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;
2180 #endif
2181 }
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;
2191 }
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;
2195 }
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;
2204 }
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;
2214 }
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;
2224 }
2225 else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
2226 #if 0
2227 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2228 state.m_sort = OpenGLState::eSortOverlayFirst;
2229 #else
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;
2233
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;
2238 #endif
2239 }
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;
2244
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;
2249 }
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;
2257 }
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;
2268 }
2269 else
2270 {
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;
2279 }
2280 break;
2281 default:
2282 // construction from IShader
2283 m_shader = QERApp_Shader_ForName( name );
2284
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;
2292
2293 if ( g_ShaderCache->useShaderLanguage() ) {
2294 state.m_program = &g_depthFillGLSL;
2295 }
2296 else
2297 {
2298 state.m_program = &g_depthFillARB;
2299 }
2300
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;
2305
2306 bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2307
2308 if ( g_ShaderCache->useShaderLanguage() ) {
2309 bumpPass.m_state |= RENDER_LIGHTING;
2310 bumpPass.m_program = &g_bumpGLSL;
2311 }
2312 else
2313 {
2314 bumpPass.m_program = &g_bumpARB;
2315 }
2316
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;
2321 }
2322 else
2323 {
2324 state.m_texture = m_shader->getTexture()->texture_number;
2325
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;
2330 }
2331 }
2332 else
2333 {
2334 state.m_state |= RENDER_CULLFACE;
2335 }
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 )
2341 {
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;
2354 }
2355 }
2356 reinterpret_cast<Vector3&>( state.m_colour ) = m_shader->getTexture()->color;
2357 state.m_colour[3] = 1.0f;
2358
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;
2368 }
2369 }
2370 else
2371 {
2372 state.m_state |= RENDER_DEPTHWRITE;
2373 state.m_sort = OpenGLState::eSortFullbright;
2374 }
2375 }
2376 }
2377 }
2378
2379
2380 #include "modulesystem/singletonmodule.h"
2381 #include "modulesystem/moduleregistry.h"
2382
2383 class OpenGLStateLibraryAPI
2384 {
2385 OpenGLStateMap m_stateMap;
2386 public:
2387 typedef OpenGLStateLibrary Type;
2388 STRING_CONSTANT( Name, "*" );
2389
OpenGLStateLibraryAPI()2390 OpenGLStateLibraryAPI(){
2391 g_openglStates = &m_stateMap;
2392 }
~OpenGLStateLibraryAPI()2393 ~OpenGLStateLibraryAPI(){
2394 g_openglStates = 0;
2395 }
getTable()2396 OpenGLStateLibrary* getTable(){
2397 return &m_stateMap;
2398 }
2399 };
2400
2401 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2402 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2403 StaticRegisterModule staticRegisterOpenGLStateLibrary( StaticOpenGLStateLibraryModule::instance() );
2404
2405 class ShaderCacheDependencies : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef
2406 {
2407 public:
ShaderCacheDependencies()2408 ShaderCacheDependencies() :
2409 GlobalShadersModuleRef( GlobalRadiant().getRequiredGameDescriptionKeyValue( "shaders" ) ){
2410 }
2411 };
2412
2413 class ShaderCacheAPI
2414 {
2415 ShaderCache* m_shaderCache;
2416 public:
2417 typedef ShaderCache Type;
2418 STRING_CONSTANT( Name, "*" );
2419
ShaderCacheAPI()2420 ShaderCacheAPI(){
2421 ShaderCache_Construct();
2422
2423 m_shaderCache = GetShaderCache();
2424 }
~ShaderCacheAPI()2425 ~ShaderCacheAPI(){
2426 ShaderCache_Destroy();
2427 }
getTable()2428 ShaderCache* getTable(){
2429 return m_shaderCache;
2430 }
2431 };
2432
2433 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2434 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2435 StaticRegisterModule staticRegisterShaderCache( StaticShaderCacheModule::instance() );
2436