]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/renderstate.cpp
it's better to close file and return on non-void function
[xonotic/netradiant.git] / radiant / renderstate.cpp
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 #define DEBUG_RENDER 0
58
59 inline void debug_string(const char *string)
60 {
61 #if (DEBUG_RENDER)
62     globalOutputStream() << string << "\n";
63 #endif
64 }
65
66 inline void debug_int(const char *comment, int i)
67 {
68 #if (DEBUG_RENDER)
69     globalOutputStream() << comment << " " << i << "\n";
70 #endif
71 }
72
73 inline void debug_colour(const char *comment)
74 {
75 #if (DEBUG_RENDER)
76                                                                                                                             Vector4 v;
77         glGetFloatv( GL_CURRENT_COLOR, reinterpret_cast<float*>( &v ) );
78         globalOutputStream() << comment << " colour: "
79                                                  << v[0] << " "
80                                                  << v[1] << " "
81                                                  << v[2] << " "
82                                                  << v[3];
83         if ( glIsEnabled( GL_COLOR_ARRAY ) ) {
84                 globalOutputStream() << " ARRAY";
85         }
86         if ( glIsEnabled( GL_COLOR_MATERIAL ) ) {
87                 globalOutputStream() << " MATERIAL";
88         }
89         globalOutputStream() << "\n";
90 #endif
91 }
92
93 #include "timer.h"
94
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;
99 Timer g_timer;
100
101 inline void count_prim()
102 {
103     ++g_count_prims;
104 }
105
106 inline void count_state()
107 {
108     ++g_count_states;
109 }
110
111 inline void count_transform()
112 {
113     ++g_count_transforms;
114 }
115
116 void Renderer_ResetStats()
117 {
118     g_count_prims = 0;
119     g_count_states = 0;
120     g_count_transforms = 0;
121     g_timer.start();
122 }
123
124 const char *Renderer_GetStats()
125 {
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();
132 }
133
134
135 void printShaderLog(GLhandleARB object)
136 {
137     GLint log_length = 0;
138     glGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length);
139
140     Array<char> log(log_length);
141     glGetInfoLogARB(object, log_length, &log_length, log.data());
142
143     globalErrorStream() << StringRange(log.begin(), log.begin() + log_length) << "\n";
144 }
145
146 void createShader(GLhandleARB program, const char *filename, GLenum type)
147 {
148     GLhandleARB shader = glCreateShaderObjectARB(type);
149     GlobalOpenGL_debugAssertNoErrors();
150
151     // load shader
152     {
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);
158
159         const GLcharARB *string = buffer.data();
160         GLint length = GLint(size);
161         glShaderSourceARB(shader, 1, &string, &length);
162     }
163
164     // compile shader
165     {
166         glCompileShaderARB(shader);
167
168         GLint compiled = 0;
169         glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
170
171         if (!compiled) {
172             printShaderLog(shader);
173         }
174
175         ASSERT_MESSAGE(compiled, "shader compile failed: " << makeQuoted(filename));
176     }
177
178     // attach shader
179     glAttachObjectARB(program, shader);
180
181     glDeleteObjectARB(shader);
182
183     GlobalOpenGL_debugAssertNoErrors();
184 }
185
186 void GLSLProgram_link(GLhandleARB program)
187 {
188     glLinkProgramARB(program);
189
190     GLint linked = false;
191     glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked);
192
193     if (!linked) {
194         printShaderLog(program);
195     }
196
197     ASSERT_MESSAGE(linked, "program link failed");
198 }
199
200 void GLSLProgram_validate(GLhandleARB program)
201 {
202     glValidateProgramARB(program);
203
204     GLint validated = false;
205     glGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated);
206
207     if (!validated) {
208         printShaderLog(program);
209     }
210
211     ASSERT_MESSAGE(validated, "program validation failed");
212 }
213
214 bool g_bumpGLSLPass_enabled = false;
215 bool g_depthfillPass_enabled = false;
216
217 class GLSLBumpProgram : public GLProgram {
218 public:
219     GLhandleARB m_program;
220     qtexture_t *m_light_attenuation_xy;
221     qtexture_t *m_light_attenuation_z;
222     GLint u_view_origin;
223     GLint u_light_origin;
224     GLint u_light_color;
225     GLint u_bump_scale;
226     GLint u_specular_exponent;
227
228     GLSLBumpProgram() : m_program(0), m_light_attenuation_xy(0), m_light_attenuation_z(0)
229     {
230     }
231
232     void create()
233     {
234         // create program
235         m_program = glCreateProgramObjectARB();
236
237         // create shader
238         {
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);
242             filename.clear();
243             filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glsl";
244             createShader(m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB);
245         }
246
247         GLSLProgram_link(m_program);
248         GLSLProgram_validate(m_program);
249
250         glUseProgramObjectARB(m_program);
251
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");
255
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);
261
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");
267
268         glUseProgramObjectARB(0);
269
270         GlobalOpenGL_debugAssertNoErrors();
271     }
272
273     void destroy()
274     {
275         glDeleteObjectARB(m_program);
276         m_program = 0;
277     }
278
279     void enable()
280     {
281         glUseProgramObjectARB(m_program);
282
283         glEnableVertexAttribArrayARB(c_attr_TexCoord0);
284         glEnableVertexAttribArrayARB(c_attr_Tangent);
285         glEnableVertexAttribArrayARB(c_attr_Binormal);
286
287         GlobalOpenGL_debugAssertNoErrors();
288
289         debug_string("enable bump");
290         g_bumpGLSLPass_enabled = true;
291     }
292
293     void disable()
294     {
295         glUseProgramObjectARB(0);
296
297         glDisableVertexAttribArrayARB(c_attr_TexCoord0);
298         glDisableVertexAttribArrayARB(c_attr_Tangent);
299         glDisableVertexAttribArrayARB(c_attr_Binormal);
300
301         GlobalOpenGL_debugAssertNoErrors();
302
303         debug_string("disable bump");
304         g_bumpGLSLPass_enabled = false;
305     }
306
307     void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
308                        const Matrix4 &world2light)
309     {
310         Matrix4 world2local(localToWorld);
311         matrix4_affine_invert(world2local);
312
313         Vector3 localLight(origin);
314         matrix4_transform_point(world2local, localLight);
315
316         Vector3 localViewer(viewer);
317         matrix4_transform_point(world2local, localViewer);
318
319         Matrix4 local2light(world2light);
320         matrix4_multiply_by_matrix4(local2light, localToWorld); // local->world->light
321
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);
327
328         glActiveTexture(GL_TEXTURE3);
329         glClientActiveTexture(GL_TEXTURE3);
330
331         glMatrixMode(GL_TEXTURE);
332         glLoadMatrixf(reinterpret_cast<const float *>( &local2light ));
333         glMatrixMode(GL_MODELVIEW);
334
335         GlobalOpenGL_debugAssertNoErrors();
336     }
337 };
338
339 GLSLBumpProgram g_bumpGLSL;
340
341
342 class GLSLDepthFillProgram : public GLProgram {
343 public:
344     GLhandleARB m_program;
345
346     void create()
347     {
348         // create program
349         m_program = glCreateProgramObjectARB();
350
351         // create shader
352         {
353             StringOutputStream filename(256);
354             filename << GlobalRadiant().getAppPath() << "gl/zfill_vp.glsl";
355             createShader(m_program, filename.c_str(), GL_VERTEX_SHADER_ARB);
356             filename.clear();
357             filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glsl";
358             createShader(m_program, filename.c_str(), GL_FRAGMENT_SHADER_ARB);
359         }
360
361         GLSLProgram_link(m_program);
362         GLSLProgram_validate(m_program);
363
364         GlobalOpenGL_debugAssertNoErrors();
365     }
366
367     void destroy()
368     {
369         glDeleteObjectARB(m_program);
370         m_program = 0;
371     }
372
373     void enable()
374     {
375         glUseProgramObjectARB(m_program);
376         GlobalOpenGL_debugAssertNoErrors();
377         debug_string("enable depthfill");
378         g_depthfillPass_enabled = true;
379     }
380
381     void disable()
382     {
383         glUseProgramObjectARB(0);
384         GlobalOpenGL_debugAssertNoErrors();
385         debug_string("disable depthfill");
386         g_depthfillPass_enabled = false;
387     }
388
389     void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
390                        const Matrix4 &world2light)
391     {
392     }
393 };
394
395 GLSLDepthFillProgram g_depthFillGLSL;
396
397
398 // ARB path
399
400 void createProgram(const char *filename, GLenum type)
401 {
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);
407
408     glProgramStringARB(type, GL_PROGRAM_FORMAT_ASCII_ARB, GLsizei(size), buffer.data());
409
410     if (GL_INVALID_OPERATION == glGetError()) {
411         GLint errPos;
412         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
413         const GLubyte *errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
414
415         globalErrorStream() << reinterpret_cast<const char *>( filename ) << ":" << errPos << "\n"
416                             << reinterpret_cast<const char *>( errString );
417
418         ERROR_MESSAGE("error in gl program");
419     }
420 }
421
422 class ARBBumpProgram : public GLProgram {
423 public:
424     GLuint m_vertex_program;
425     GLuint m_fragment_program;
426
427     void create()
428     {
429         glEnable(GL_VERTEX_PROGRAM_ARB);
430         glEnable(GL_FRAGMENT_PROGRAM_ARB);
431
432         {
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);
438
439             glGenProgramsARB(1, &m_fragment_program);
440             glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
441             filename.clear();
442             filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.glp";
443             createProgram(filename.c_str(), GL_FRAGMENT_PROGRAM_ARB);
444         }
445
446         glDisable(GL_VERTEX_PROGRAM_ARB);
447         glDisable(GL_FRAGMENT_PROGRAM_ARB);
448
449         GlobalOpenGL_debugAssertNoErrors();
450     }
451
452     void destroy()
453     {
454         glDeleteProgramsARB(1, &m_vertex_program);
455         glDeleteProgramsARB(1, &m_fragment_program);
456         GlobalOpenGL_debugAssertNoErrors();
457     }
458
459     void enable()
460     {
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);
465
466         glEnableVertexAttribArrayARB(8);
467         glEnableVertexAttribArrayARB(9);
468         glEnableVertexAttribArrayARB(10);
469         glEnableVertexAttribArrayARB(11);
470
471         GlobalOpenGL_debugAssertNoErrors();
472     }
473
474     void disable()
475     {
476         glDisable(GL_VERTEX_PROGRAM_ARB);
477         glDisable(GL_FRAGMENT_PROGRAM_ARB);
478
479         glDisableVertexAttribArrayARB(8);
480         glDisableVertexAttribArrayARB(9);
481         glDisableVertexAttribArrayARB(10);
482         glDisableVertexAttribArrayARB(11);
483
484         GlobalOpenGL_debugAssertNoErrors();
485     }
486
487     void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
488                        const Matrix4 &world2light)
489     {
490         Matrix4 world2local(localToWorld);
491         matrix4_affine_invert(world2local);
492
493         Vector3 localLight(origin);
494         matrix4_transform_point(world2local, localLight);
495
496         Vector3 localViewer(viewer);
497         matrix4_transform_point(world2local, localViewer);
498
499         Matrix4 local2light(world2light);
500         matrix4_multiply_by_matrix4(local2light, localToWorld); // local->world->light
501
502         // view origin
503         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 4, localViewer.x(), localViewer.y(), localViewer.z(), 0);
504
505         // light origin
506         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, localLight.x(), localLight.y(), localLight.z(), 1);
507
508         // light colour
509         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 3, colour.x(), colour.y(), colour.z(), 0);
510
511         // bump scale
512         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1, 0, 0, 0);
513
514         // specular exponent
515         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 5, 32, 0, 0, 0);
516
517
518         glActiveTexture(GL_TEXTURE3);
519         glClientActiveTexture(GL_TEXTURE3);
520
521         glMatrixMode(GL_TEXTURE);
522         glLoadMatrixf(reinterpret_cast<const float *>( &local2light ));
523         glMatrixMode(GL_MODELVIEW);
524
525         GlobalOpenGL_debugAssertNoErrors();
526     }
527 };
528
529 class ARBDepthFillProgram : public GLProgram {
530 public:
531     GLuint m_vertex_program;
532     GLuint m_fragment_program;
533
534     void create()
535     {
536         glEnable(GL_VERTEX_PROGRAM_ARB);
537         glEnable(GL_FRAGMENT_PROGRAM_ARB);
538
539         {
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);
545
546             glGenProgramsARB(1, &m_fragment_program);
547             glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_fragment_program);
548             filename.clear();
549             filename << GlobalRadiant().getAppPath() << "gl/zfill_fp.glp";
550             createProgram(filename.c_str(), GL_FRAGMENT_PROGRAM_ARB);
551         }
552
553         glDisable(GL_VERTEX_PROGRAM_ARB);
554         glDisable(GL_FRAGMENT_PROGRAM_ARB);
555
556         GlobalOpenGL_debugAssertNoErrors();
557     }
558
559     void destroy()
560     {
561         glDeleteProgramsARB(1, &m_vertex_program);
562         glDeleteProgramsARB(1, &m_fragment_program);
563         GlobalOpenGL_debugAssertNoErrors();
564     }
565
566     void enable()
567     {
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);
572
573         GlobalOpenGL_debugAssertNoErrors();
574     }
575
576     void disable()
577     {
578         glDisable(GL_VERTEX_PROGRAM_ARB);
579         glDisable(GL_FRAGMENT_PROGRAM_ARB);
580
581         GlobalOpenGL_debugAssertNoErrors();
582     }
583
584     void setParameters(const Vector3 &viewer, const Matrix4 &localToWorld, const Vector3 &origin, const Vector3 &colour,
585                        const Matrix4 &world2light)
586     {
587     }
588 };
589
590 ARBBumpProgram g_bumpARB;
591 ARBDepthFillProgram g_depthFillARB;
592
593
594 #if 0
595                                                                                                                         // NV20 path (unfinished)
596
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 );
603
604         glLoadProgramNV( type, program, GLsizei( size ), buffer.data() );
605
606         if ( GL_INVALID_OPERATION == glGetError() ) {
607                 GLint errPos;
608                 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
609                 const GLubyte* errString = glGetString( GL_PROGRAM_ERROR_STRING_NV );
610
611                 globalErrorStream() << filename << ":" <<  errPos << "\n" << errString;
612
613                 ERROR_MESSAGE( "error in gl program" );
614         }
615 }
616
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;
623
624 void createVertexProgram(){
625         {
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 );
631
632                 glGenProgramsNV( 1, &m_fragment_program );
633                 glBindProgramNV( GL_FRAGMENT_PROGRAM_NV, m_fragment_program );
634                 filename.clear();
635                 filename << GlobalRadiant().getAppPath() << "gl/lighting_DBS_omni_fp.nv30";
636                 createProgram( m_fragment_program, filename.c_str(), GL_FRAGMENT_PROGRAM_NV );
637         }
638
639         g_cube = GlobalTexturesCache().capture( "generated/cube" );
640         g_specular_lookup = GlobalTexturesCache().capture( "generated/specular" );
641
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 );
647
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 );
653
654         GlobalOpenGL_debugAssertNoErrors();
655 }
656
657 void destroyVertexProgram(){
658         glDeleteProgramsNV( 1, &m_vertex_program );
659         glDeleteProgramsNV( 1, &m_fragment_program );
660         GlobalOpenGL_debugAssertNoErrors();
661
662         GlobalTexturesCache().release( g_cube );
663         GlobalTexturesCache().release( g_specular_lookup );
664         GlobalTexturesCache().release( g_attenuation_xy );
665         GlobalTexturesCache().release( g_attenuation_z );
666 }
667
668 bool g_vertexProgram_enabled = false;
669
670 void enableVertexProgram(){
671         //set up the register combiners
672         //two general combiners
673         glCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
674
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 );
686
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 );
694
695
696
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 );
701
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 );
707
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 );
712
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 );
721
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 );
726
727         GlobalOpenGL_debugAssertNoErrors();
728         g_vertexProgram_enabled = true;
729 }
730
731 void disableVertexProgram(){
732         glDisable( GL_VERTEX_PROGRAM_NV );
733         glDisable( GL_REGISTER_COMBINERS_NV );
734
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 );
743
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 );
748
749         GlobalOpenGL_debugAssertNoErrors();
750         g_vertexProgram_enabled = false;
751 }
752
753 class GLstringNV
754 {
755 public:
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 ) ) ){
759 }
760 };
761
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" );
767
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 ) );
774
775         glActiveTexture( GL_TEXTURE3 );
776         glClientActiveTexture( GL_TEXTURE3 );
777
778         glMatrixMode( GL_TEXTURE );
779         glLoadMatrixf( reinterpret_cast<const float*>( &local2light ) );
780         glMatrixMode( GL_MODELVIEW );
781
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 );
784
785         // view origin
786         //qglProgramNamedParameter4fNV(m_fragment_program, g_view_origin.m_length, g_view_origin.m_string, localViewer.x(), localViewer.y(), localViewer.z(), 0);
787
788         // light origin
789         glProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 8, localViewer.x(), localViewer.y(), localViewer.z(), 1.0f );
790
791         // light colour
792         glCombinerParameterfNV( GL_CONSTANT_COLOR0_NV, 1, 1, 1, 1 )
793
794         // bump scale
795         //qglProgramNamedParameter4fNV(m_fragment_program, g_bumpGLSL_scale.m_length, g_bumpGLSL_scale.m_string, 1, 0, 0, 0);
796
797         // specular exponent
798         //qglProgramNamedParameter4fNV(m_fragment_program, g_specular_exponent.m_length, g_specular_exponent.m_string, 32, 0, 0, 0);
799
800         GlobalOpenGL_debugAssertNoErrors();
801 }
802
803 #endif
804
805
806 bool g_vertexArray_enabled = false;
807 bool g_normalArray_enabled = false;
808 bool g_texcoordArray_enabled = false;
809 bool g_colorArray_enabled = false;
810
811 inline bool OpenGLState_less(const OpenGLState &self, const OpenGLState &other)
812 {
813     //! Sort by sort-order override.
814     if (self.m_sort != other.m_sort) {
815         return self.m_sort < other.m_sort;
816     }
817     //! Sort by texture handle.
818     if (self.m_texture != other.m_texture) {
819         return self.m_texture < other.m_texture;
820     }
821     if (self.m_texture1 != other.m_texture1) {
822         return self.m_texture1 < other.m_texture1;
823     }
824     if (self.m_texture2 != other.m_texture2) {
825         return self.m_texture2 < other.m_texture2;
826     }
827     if (self.m_texture3 != other.m_texture3) {
828         return self.m_texture3 < other.m_texture3;
829     }
830     if (self.m_texture4 != other.m_texture4) {
831         return self.m_texture4 < other.m_texture4;
832     }
833     if (self.m_texture5 != other.m_texture5) {
834         return self.m_texture5 < other.m_texture5;
835     }
836     if (self.m_texture6 != other.m_texture6) {
837         return self.m_texture6 < other.m_texture6;
838     }
839     if (self.m_texture7 != other.m_texture7) {
840         return self.m_texture7 < other.m_texture7;
841     }
842     //! Sort by state bit-vector.
843     if (self.m_state != other.m_state) {
844         return self.m_state < other.m_state;
845     }
846     //! Comparing address makes sure states are never equal.
847     return &self < &other;
848 }
849
850 void OpenGLState_constructDefault(OpenGLState &state)
851 {
852     state.m_state = RENDER_DEFAULT;
853
854     state.m_texture = 0;
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;
862
863     state.m_colour[0] = 1;
864     state.m_colour[1] = 1;
865     state.m_colour[2] = 1;
866     state.m_colour[3] = 1;
867
868     state.m_depthfunc = GL_LESS;
869
870     state.m_blend_src = GL_SRC_ALPHA;
871     state.m_blend_dst = GL_ONE_MINUS_SRC_ALPHA;
872
873     state.m_alphafunc = GL_ALWAYS;
874     state.m_alpharef = 0;
875
876     state.m_linewidth = 1;
877     state.m_pointsize = 1;
878
879     state.m_linestipple_factor = 1;
880     state.m_linestipple_pattern = 0xaaaa;
881
882     state.m_fog = OpenGLFogState();
883 }
884
885
886 /// \brief A container of Renderable references.
887 /// May contain the same Renderable multiple times, with different transforms.
888 class OpenGLStateBucket {
889 public:
890     struct RenderTransform {
891         const Matrix4 *m_transform;
892         const OpenGLRenderable *m_renderable;
893         const RendererLight *m_light;
894
895         RenderTransform(const OpenGLRenderable &renderable, const Matrix4 &transform, const RendererLight *light)
896                 : m_transform(&transform), m_renderable(&renderable), m_light(light)
897         {
898         }
899     };
900
901     typedef std::vector<RenderTransform> Renderables;
902
903 private:
904
905     OpenGLState m_state;
906     Renderables m_renderables;
907
908 public:
909     OpenGLStateBucket()
910     {
911     }
912
913     void addRenderable(const OpenGLRenderable &renderable, const Matrix4 &modelview, const RendererLight *light = 0)
914     {
915         m_renderables.push_back(RenderTransform(renderable, modelview, light));
916     }
917
918     OpenGLState &state()
919     {
920         return m_state;
921     }
922
923     void render(OpenGLState &current, unsigned int globalstate, const Vector3 &viewer);
924 };
925
926 #define LIGHT_SHADER_DEBUG 0
927
928 #if LIGHT_SHADER_DEBUG
929                                                                                                                         typedef std::vector<Shader*> LightDebugShaders;
930 LightDebugShaders g_lightDebugShaders;
931 #endif
932
933 class OpenGLStateLess {
934 public:
935     bool operator()(const OpenGLState &self, const OpenGLState &other) const
936     {
937         return OpenGLState_less(self, other);
938     }
939 };
940
941 typedef ConstReference<OpenGLState> OpenGLStateReference;
942 typedef std::map<OpenGLStateReference, OpenGLStateBucket *, OpenGLStateLess> OpenGLStates;
943 OpenGLStates g_state_sorted;
944
945 class OpenGLStateBucketAdd {
946     OpenGLStateBucket &m_bucket;
947     const OpenGLRenderable &m_renderable;
948     const Matrix4 &m_modelview;
949 public:
950     using func = void(const RendererLight &);
951
952     OpenGLStateBucketAdd(OpenGLStateBucket &bucket, const OpenGLRenderable &renderable, const Matrix4 &modelview) :
953             m_bucket(bucket), m_renderable(renderable), m_modelview(modelview)
954     {
955     }
956
957     void operator()(const RendererLight &light)
958     {
959         m_bucket.addRenderable(m_renderable, m_modelview, &light);
960     }
961 };
962
963 class CountLights {
964     std::size_t m_count;
965 public:
966     using func = void(RendererLight &);
967
968     CountLights() : m_count(0)
969     {
970     }
971
972     void operator()(const RendererLight &light)
973     {
974         ++m_count;
975     }
976
977     std::size_t count() const
978     {
979         return m_count;
980     }
981 };
982
983 class OpenGLShader : public Shader {
984     typedef std::list<OpenGLStateBucket *> Passes;
985     Passes m_passes;
986     IShader *m_shader;
987     std::size_t m_used;
988     ModuleObservers m_observers;
989 public:
990     OpenGLShader() : m_shader(0), m_used(0)
991     {
992     }
993
994     ~OpenGLShader()
995     {
996     }
997
998     void construct(const char *name);
999
1000     void destroy()
1001     {
1002         if (m_shader) {
1003             m_shader->DecRef();
1004         }
1005         m_shader = 0;
1006
1007         for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1008             delete *i;
1009         }
1010         m_passes.clear();
1011     }
1012
1013     void addRenderable(const OpenGLRenderable &renderable, const Matrix4 &modelview, const LightList *lights)
1014     {
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 )
1023                                 {
1024                                         g_lightDebugShaders[counter.count()]->addRenderable( renderable, modelview );
1025                                 }
1026                         }
1027                 }
1028                 else
1029 #else
1030             if (((*i)->state().m_state & RENDER_BUMP) != 0) {
1031                 if (lights != 0) {
1032                     OpenGLStateBucketAdd add(*(*i), renderable, modelview);
1033                     lights->forEachLight(makeCallback(add));
1034                 }
1035             } else
1036 #endif
1037             {
1038                 (*i)->addRenderable(renderable, modelview);
1039             }
1040         }
1041     }
1042
1043     void incrementUsed()
1044     {
1045         if (++m_used == 1 && m_shader != 0) {
1046             m_shader->SetInUse(true);
1047         }
1048     }
1049
1050     void decrementUsed()
1051     {
1052         if (--m_used == 0 && m_shader != 0) {
1053             m_shader->SetInUse(false);
1054         }
1055     }
1056
1057     bool realised() const
1058     {
1059         return m_shader != 0;
1060     }
1061
1062     void attach(ModuleObserver &observer)
1063     {
1064         if (realised()) {
1065             observer.realise();
1066         }
1067         m_observers.attach(observer);
1068     }
1069
1070     void detach(ModuleObserver &observer)
1071     {
1072         if (realised()) {
1073             observer.unrealise();
1074         }
1075         m_observers.detach(observer);
1076     }
1077
1078     void realise(const CopiedString &name)
1079     {
1080         construct(name.c_str());
1081
1082         if (m_used != 0 && m_shader != 0) {
1083             m_shader->SetInUse(true);
1084         }
1085
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));
1088         }
1089
1090         m_observers.realise();
1091     }
1092
1093     void unrealise()
1094     {
1095         m_observers.unrealise();
1096
1097         for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
1098             g_state_sorted.erase(OpenGLStateReference((*i)->state()));
1099         }
1100
1101         destroy();
1102     }
1103
1104     qtexture_t &getTexture() const
1105     {
1106         ASSERT_NOTNULL(m_shader);
1107         return *m_shader->getTexture();
1108     }
1109
1110     unsigned int getFlags() const
1111     {
1112         ASSERT_NOTNULL(m_shader);
1113         return m_shader->getFlags();
1114     }
1115
1116     IShader &getShader() const
1117     {
1118         ASSERT_NOTNULL(m_shader);
1119         return *m_shader;
1120     }
1121
1122     OpenGLState &appendDefaultPass()
1123     {
1124         m_passes.push_back(new OpenGLStateBucket);
1125         OpenGLState &state = m_passes.back()->state();
1126         OpenGLState_constructDefault(state);
1127         return state;
1128     }
1129 };
1130
1131
1132 inline bool lightEnabled(const RendererLight &light, const LightCullable &cullable)
1133 {
1134     return cullable.testLight(light);
1135 }
1136
1137 typedef std::set<RendererLight *> RendererLights;
1138
1139 #define DEBUG_LIGHT_SYNC 0
1140
1141 class LinearLightList : public LightList {
1142     LightCullable &m_cullable;
1143     RendererLights &m_allLights;
1144     Callback<void()> m_evaluateChanged;
1145
1146     typedef std::list<RendererLight *> Lights;
1147     mutable Lights m_lights;
1148     mutable bool m_lightsChanged;
1149 public:
1150     LinearLightList(LightCullable &cullable, RendererLights &lights, const Callback<void()> &evaluateChanged) :
1151             m_cullable(cullable), m_allLights(lights), m_evaluateChanged(evaluateChanged)
1152     {
1153         m_lightsChanged = true;
1154     }
1155
1156     void evaluateLights() const
1157     {
1158         m_evaluateChanged();
1159         if (m_lightsChanged) {
1160             m_lightsChanged = false;
1161
1162             m_lights.clear();
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));
1168                 }
1169             }
1170         }
1171 #if (DEBUG_LIGHT_SYNC)
1172                                                                                                                                 else
1173         {
1174                 Lights lights;
1175                 for ( RendererLights::const_iterator i = m_allLights.begin(); i != m_allLights.end(); ++i )
1176                 {
1177                         if ( lightEnabled( *( *i ), m_cullable ) ) {
1178                                 lights.push_back( *i );
1179                         }
1180                 }
1181                 ASSERT_MESSAGE(
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"
1185                         );
1186         }
1187 #endif
1188     }
1189
1190     void forEachLight(const RendererLightCallback &callback) const
1191     {
1192         evaluateLights();
1193
1194         for (Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) {
1195             callback(*(*i));
1196         }
1197     }
1198
1199     void lightsChanged() const
1200     {
1201         m_lightsChanged = true;
1202     }
1203 };
1204
1205 inline void setFogState(const OpenGLFogState &state)
1206 {
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));
1213 }
1214
1215 #define DEBUG_SHADERS 0
1216
1217 class OpenGLShaderCache : public ShaderCache, public TexturesCacheObserver, public ModuleObserver {
1218     class CreateOpenGLShader {
1219         OpenGLShaderCache *m_cache;
1220     public:
1221         explicit CreateOpenGLShader(OpenGLShaderCache *cache = 0)
1222                 : m_cache(cache)
1223         {
1224         }
1225
1226         OpenGLShader *construct(const CopiedString &name)
1227         {
1228             OpenGLShader *shader = new OpenGLShader;
1229             if (m_cache->realised()) {
1230                 shader->realise(name);
1231             }
1232             return shader;
1233         }
1234
1235         void destroy(OpenGLShader *shader)
1236         {
1237             if (m_cache->realised()) {
1238                 shader->unrealise();
1239             }
1240             delete shader;
1241         }
1242     };
1243
1244     typedef HashedCache<CopiedString, OpenGLShader, HashString, std::equal_to<CopiedString>, CreateOpenGLShader> Shaders;
1245     Shaders m_shaders;
1246     std::size_t m_unrealised;
1247
1248     bool m_lightingEnabled;
1249     bool m_lightingSupported;
1250     bool m_useShaderLanguage;
1251
1252 public:
1253     OpenGLShaderCache()
1254             : m_shaders(CreateOpenGLShader(this)),
1255               m_unrealised(
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)
1262     {
1263     }
1264
1265     ~OpenGLShaderCache()
1266     {
1267         for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
1268             globalOutputStream() << "leaked shader: " << makeQuoted((*i).key.c_str()) << "\n";
1269         }
1270     }
1271
1272     Shader *capture(const char *name)
1273     {
1274         ASSERT_MESSAGE(name[0] == '$'
1275                        || *name == '['
1276                        || *name == '<'
1277                        || *name == '('
1278                        || strchr(name, '\\') == 0, "shader name contains invalid characters: \"" << name << "\"");
1279 #if DEBUG_SHADERS
1280         globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
1281 #endif
1282         return m_shaders.capture(name).get();
1283     }
1284
1285     void release(const char *name)
1286     {
1287 #if DEBUG_SHADERS
1288         globalOutputStream() << "shaders release: " << makeQuoted( name ) << '\n';
1289 #endif
1290         m_shaders.release(name);
1291     }
1292
1293     void
1294     render(RenderStateFlags globalstate, const Matrix4 &modelview, const Matrix4 &projection, const Vector3 &viewer)
1295     {
1296         glMatrixMode(GL_PROJECTION);
1297         glLoadMatrixf(reinterpret_cast<const float *>( &projection ));
1298 #if 0
1299         //qglGetFloatv(GL_PROJECTION_MATRIX, reinterpret_cast<float*>(&projection));
1300 #endif
1301
1302         glMatrixMode(GL_MODELVIEW);
1303         glLoadMatrixf(reinterpret_cast<const float *>( &modelview ));
1304 #if 0
1305         //qglGetFloatv(GL_MODELVIEW_MATRIX, reinterpret_cast<float*>(&modelview));
1306 #endif
1307
1308         ASSERT_MESSAGE(realised(), "render states are not realised");
1309
1310         // global settings that are not set in renderstates
1311         glFrontFace(GL_CW);
1312         glCullFace(GL_BACK);
1313         glPolygonOffset(-1, 1);
1314         {
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
1332             };
1333             glPolygonStipple(pattern);
1334         }
1335         glEnableClientState(GL_VERTEX_ARRAY);
1336         g_vertexArray_enabled = true;
1337         glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
1338
1339         if (GlobalOpenGL().GL_1_3()) {
1340             glActiveTexture(GL_TEXTURE0);
1341             glClientActiveTexture(GL_TEXTURE0);
1342         }
1343
1344         if (GlobalOpenGL().ARB_shader_objects()) {
1345             glUseProgramObjectARB(0);
1346             glDisableVertexAttribArrayARB(c_attr_TexCoord0);
1347             glDisableVertexAttribArrayARB(c_attr_Tangent);
1348             glDisableVertexAttribArrayARB(c_attr_Binormal);
1349         }
1350
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);
1354         }
1355
1356         OpenGLState current;
1357         OpenGLState_constructDefault(current);
1358         current.m_sort = OpenGLState::eSortFirst;
1359
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);
1382
1383         glBindTexture(GL_TEXTURE_2D, 0);
1384         glColor4f(1, 1, 1, 1);
1385         glDepthFunc(GL_LESS);
1386         glAlphaFunc(GL_ALWAYS, 0);
1387         glLineWidth(1);
1388         glPointSize(1);
1389
1390         glHint(GL_FOG_HINT, GL_NICEST);
1391         glDisable(GL_FOG);
1392         setFogState(OpenGLFogState());
1393
1394         GlobalOpenGL_debugAssertNoErrors();
1395
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);
1399         }
1400         debug_string("end rendering");
1401     }
1402
1403     void realise()
1404     {
1405         if (--m_unrealised == 0) {
1406             if (lightingSupported() && lightingEnabled()) {
1407                 if (useShaderLanguage()) {
1408                     g_bumpGLSL.create();
1409                     g_depthFillGLSL.create();
1410                 } else {
1411                     g_bumpARB.create();
1412                     g_depthFillARB.create();
1413                 }
1414             }
1415
1416             for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
1417                 if (!(*i).value.empty()) {
1418                     (*i).value->realise(i->key);
1419                 }
1420             }
1421         }
1422     }
1423
1424     void unrealise()
1425     {
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();
1430                 }
1431             }
1432             if (GlobalOpenGL().contextValid && lightingSupported() && lightingEnabled()) {
1433                 if (useShaderLanguage()) {
1434                     g_bumpGLSL.destroy();
1435                     g_depthFillGLSL.destroy();
1436                 } else {
1437                     g_bumpARB.destroy();
1438                     g_depthFillARB.destroy();
1439                 }
1440             }
1441         }
1442     }
1443
1444     bool realised()
1445     {
1446         return m_unrealised == 0;
1447     }
1448
1449
1450     bool lightingEnabled() const
1451     {
1452         return m_lightingEnabled;
1453     }
1454
1455     bool lightingSupported() const
1456     {
1457         return m_lightingSupported;
1458     }
1459
1460     bool useShaderLanguage() const
1461     {
1462         return m_useShaderLanguage;
1463     }
1464
1465     void setLighting(bool supported, bool enabled)
1466     {
1467         bool refresh = (m_lightingSupported && m_lightingEnabled) != (supported && enabled);
1468
1469         if (refresh) {
1470             unrealise();
1471             GlobalShaderSystem().setLightingEnabled(supported && enabled);
1472         }
1473
1474         m_lightingSupported = supported;
1475         m_lightingEnabled = enabled;
1476
1477         if (refresh) {
1478             realise();
1479         }
1480     }
1481
1482     void extensionsInitialised()
1483     {
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(),
1491                     m_lightingEnabled
1492         );
1493
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";
1498             }
1499             if (!GlobalOpenGL().ARB_vertex_program()) {
1500                 globalOutputStream() << "  GL_ARB_vertex_program\n";
1501             }
1502             if (!GlobalOpenGL().ARB_fragment_program()) {
1503                 globalOutputStream() << "  GL_ARB_fragment_program\n";
1504             }
1505             if (!GlobalOpenGL().ARB_shader_objects()) {
1506                 globalOutputStream() << "  GL_ARB_shader_objects\n";
1507             }
1508             if (!GlobalOpenGL().ARB_vertex_shader()) {
1509                 globalOutputStream() << "  GL_ARB_vertex_shader\n";
1510             }
1511             if (!GlobalOpenGL().ARB_fragment_shader()) {
1512                 globalOutputStream() << "  GL_ARB_fragment_shader\n";
1513             }
1514             if (!GlobalOpenGL().ARB_shading_language_100()) {
1515                 globalOutputStream() << "  GL_ARB_shading_language_100\n";
1516             }
1517         }
1518     }
1519
1520     void setLightingEnabled(bool enabled)
1521     {
1522         setLighting(m_lightingSupported, enabled);
1523     }
1524
1525 // light culling
1526
1527     RendererLights m_lights;
1528     bool m_lightsChanged;
1529     typedef std::map<LightCullable *, LinearLightList> LightLists;
1530     LightLists m_lightLists;
1531
1532     const LightList &attach(LightCullable &cullable)
1533     {
1534         return (*m_lightLists.insert(LightLists::value_type(&cullable, LinearLightList(cullable, m_lights,
1535                                                                                        EvaluateChangedCaller(
1536                                                                                                *this)))).first).second;
1537     }
1538
1539     void detach(LightCullable &cullable)
1540     {
1541         m_lightLists.erase(&cullable);
1542     }
1543
1544     void changed(LightCullable &cullable)
1545     {
1546         LightLists::iterator i = m_lightLists.find(&cullable);
1547         ASSERT_MESSAGE(i != m_lightLists.end(), "cullable not attached");
1548         (*i).second.lightsChanged();
1549     }
1550
1551     void attach(RendererLight &light)
1552     {
1553         ASSERT_MESSAGE(m_lights.find(&light) == m_lights.end(), "light could not be attached");
1554         m_lights.insert(&light);
1555         changed(light);
1556     }
1557
1558     void detach(RendererLight &light)
1559     {
1560         ASSERT_MESSAGE(m_lights.find(&light) != m_lights.end(), "light could not be detached");
1561         m_lights.erase(&light);
1562         changed(light);
1563     }
1564
1565     void changed(RendererLight &light)
1566     {
1567         m_lightsChanged = true;
1568     }
1569
1570     void evaluateChanged()
1571     {
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();
1576             }
1577         }
1578     }
1579
1580     typedef MemberCaller<OpenGLShaderCache, void(), &OpenGLShaderCache::evaluateChanged> EvaluateChangedCaller;
1581
1582     typedef std::set<const Renderable *> Renderables;
1583     Renderables m_renderables;
1584     mutable bool m_traverseRenderablesMutex;
1585
1586 // renderables
1587     void attachRenderable(const Renderable &renderable)
1588     {
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);
1592     }
1593
1594     void detachRenderable(const Renderable &renderable)
1595     {
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);
1599     }
1600
1601     void forEachRenderable(const RenderableCallback &callback) const
1602     {
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) {
1606             callback(*(*i));
1607         }
1608         m_traverseRenderablesMutex = false;
1609     }
1610 };
1611
1612 static OpenGLShaderCache *g_ShaderCache;
1613
1614 void ShaderCache_extensionsInitialised()
1615 {
1616     g_ShaderCache->extensionsInitialised();
1617 }
1618
1619 void ShaderCache_setBumpEnabled(bool enabled)
1620 {
1621     g_ShaderCache->setLightingEnabled(enabled);
1622 }
1623
1624
1625 Vector3 g_DebugShaderColours[256];
1626 Shader *g_defaultPointLight = 0;
1627
1628 void ShaderCache_Construct()
1629 {
1630     g_ShaderCache = new OpenGLShaderCache;
1631     GlobalTexturesCache().attach(*g_ShaderCache);
1632     GlobalShaderSystem().attach(*g_ShaderCache);
1633
1634     if (g_pGameDescription->mGameType == "doom3") {
1635         g_defaultPointLight = g_ShaderCache->capture("lights/defaultPointLight");
1636         //Shader* overbright =
1637         g_ShaderCache->capture("$OVERBRIGHT");
1638
1639 #if LIGHT_SHADER_DEBUG
1640                                                                                                                                 for ( std::size_t i = 0; i < 256; ++i )
1641                 {
1642                         g_DebugShaderColours[i] = Vector3( i / 256.0, i / 256.0, i / 256.0 );
1643                 }
1644
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 );
1657
1658                 g_lightDebugShaders.reserve( 256 );
1659                 StringOutputStream buffer( 256 );
1660                 for ( std::size_t i = 0; i < 256; ++i )
1661                 {
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() ) );
1664                         buffer.clear();
1665                 }
1666 #endif
1667     }
1668 }
1669
1670 void ShaderCache_Destroy()
1671 {
1672     if (g_pGameDescription->mGameType == "doom3") {
1673         g_ShaderCache->release("lights/defaultPointLight");
1674         g_ShaderCache->release("$OVERBRIGHT");
1675         g_defaultPointLight = 0;
1676
1677 #if LIGHT_SHADER_DEBUG
1678                                                                                                                                 g_lightDebugShaders.clear();
1679                 StringOutputStream buffer( 256 );
1680                 for ( std::size_t i = 0; i < 256; ++i )
1681                 {
1682                         buffer << "(" << g_DebugShaderColours[i].x() << " " << g_DebugShaderColours[i].y() << " " << g_DebugShaderColours[i].z() << ")";
1683                         g_ShaderCache->release( buffer.c_str() );
1684                 }
1685 #endif
1686     }
1687
1688     GlobalShaderSystem().detach(*g_ShaderCache);
1689     GlobalTexturesCache().detach(*g_ShaderCache);
1690     delete g_ShaderCache;
1691 }
1692
1693 ShaderCache *GetShaderCache()
1694 {
1695     return g_ShaderCache;
1696 }
1697
1698 inline void setTextureState(GLint &current, const GLint &texture, GLenum textureUnit)
1699 {
1700     if (texture != current) {
1701         glActiveTexture(textureUnit);
1702         glClientActiveTexture(textureUnit);
1703         glBindTexture(GL_TEXTURE_2D, texture);
1704         GlobalOpenGL_debugAssertNoErrors();
1705         current = texture;
1706     }
1707 }
1708
1709 inline void setTextureState(GLint &current, const GLint &texture)
1710 {
1711     if (texture != current) {
1712         glBindTexture(GL_TEXTURE_2D, texture);
1713         GlobalOpenGL_debugAssertNoErrors();
1714         current = texture;
1715     }
1716 }
1717
1718 inline void setState(unsigned int state, unsigned int delta, unsigned int flag, GLenum glflag)
1719 {
1720     if (delta & state & flag) {
1721         glEnable(glflag);
1722         GlobalOpenGL_debugAssertNoErrors();
1723     } else if (delta & ~state & flag) {
1724         glDisable(glflag);
1725         GlobalOpenGL_debugAssertNoErrors();
1726     }
1727 }
1728
1729 void OpenGLState_apply(const OpenGLState &self, OpenGLState &current, unsigned int globalstate)
1730 {
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)));
1735
1736     count_state();
1737
1738     if (self.m_state & RENDER_OVERRIDE) {
1739         globalstate |= RENDER_FILL | RENDER_DEPTHWRITE;
1740     }
1741
1742     const unsigned int state = self.m_state & globalstate;
1743     const unsigned int delta = state ^current.m_state;
1744
1745     GlobalOpenGL_debugAssertNoErrors();
1746
1747     GLProgram *program = (state & RENDER_PROGRAM) != 0 ? self.m_program : 0;
1748
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");
1754         }
1755
1756         current.m_program = program;
1757
1758         if (current.m_program != 0) {
1759             current.m_program->enable();
1760         }
1761     }
1762
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();
1771     }
1772
1773     setState(state, delta, RENDER_OFFSETLINE, GL_POLYGON_OFFSET_LINE);
1774
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;
1789     }
1790
1791     if (delta & state & RENDER_TEXTURE) {
1792         GlobalOpenGL_debugAssertNoErrors();
1793
1794         if (GlobalOpenGL().GL_1_3()) {
1795             glActiveTexture(GL_TEXTURE0);
1796             glClientActiveTexture(GL_TEXTURE0);
1797         }
1798
1799         glEnable(GL_TEXTURE_2D);
1800
1801         glColor4f(1, 1, 1, self.m_colour[3]);
1802         debug_colour("setting texture");
1803
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);
1811         }
1812
1813         glDisable(GL_TEXTURE_2D);
1814         glBindTexture(GL_TEXTURE_2D, 0);
1815         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1816
1817         GlobalOpenGL_debugAssertNoErrors();
1818         g_texcoordArray_enabled = false;
1819     }
1820
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
1827
1828         glEnable(GL_BLEND);
1829         if (GlobalOpenGL().GL_1_3()) {
1830             glActiveTexture(GL_TEXTURE0);
1831         }
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);
1838         }
1839         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1840         GlobalOpenGL_debugAssertNoErrors();
1841     }
1842
1843     setState(state, delta, RENDER_CULLFACE, GL_CULL_FACE);
1844
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();
1851     }
1852
1853     setState(state, delta, RENDER_SCALED, GL_NORMALIZE); // not GL_RESCALE_NORMAL
1854
1855     setState(state, delta, RENDER_DEPTHTEST, GL_DEPTH_TEST);
1856
1857     if (delta & state & RENDER_DEPTHWRITE) {
1858         glDepthMask(GL_TRUE);
1859
1860 #if DEBUG_RENDER
1861                                                                                                                                 GLboolean depthEnabled;
1862                 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1863                 ASSERT_MESSAGE( depthEnabled, "failed to set depth buffer mask bit" );
1864 #endif
1865         debug_string("enabled depth-buffer writing");
1866
1867         GlobalOpenGL_debugAssertNoErrors();
1868     } else if (delta & ~state & RENDER_DEPTHWRITE) {
1869         glDepthMask(GL_FALSE);
1870
1871 #if DEBUG_RENDER
1872                                                                                                                                 GLboolean depthEnabled;
1873                 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
1874                 ASSERT_MESSAGE( !depthEnabled, "failed to set depth buffer mask bit" );
1875 #endif
1876         debug_string("disabled depth-buffer writing");
1877
1878         GlobalOpenGL_debugAssertNoErrors();
1879     }
1880
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();
1887     }
1888
1889     setState(state, delta, RENDER_ALPHATEST, GL_ALPHA_TEST);
1890
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;
1902     }
1903
1904     if (delta & ~state & RENDER_COLOURCHANGE) {
1905         glColor4fv(vector4_to_array(self.m_colour));
1906         GlobalOpenGL_debugAssertNoErrors();
1907     }
1908
1909     setState(state, delta, RENDER_LINESTIPPLE, GL_LINE_STIPPLE);
1910     setState(state, delta, RENDER_LINESMOOTH, GL_LINE_SMOOTH);
1911
1912     setState(state, delta, RENDER_POLYGONSTIPPLE, GL_POLYGON_STIPPLE);
1913     setState(state, delta, RENDER_POLYGONSMOOTH, GL_POLYGON_SMOOTH);
1914
1915     setState(state, delta, RENDER_FOG, GL_FOG);
1916
1917     if ((state & RENDER_FOG) != 0) {
1918         setFogState(self.m_fog);
1919         GlobalOpenGL_debugAssertNoErrors();
1920         current.m_fog = self.m_fog;
1921     }
1922
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;
1927     }
1928
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;
1936     }
1937
1938
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;
1946     }
1947
1948     {
1949         GLint texture0 = 0;
1950         GLint texture1 = 0;
1951         GLint texture2 = 0;
1952         GLint texture3 = 0;
1953         GLint texture4 = 0;
1954         GLint texture5 = 0;
1955         GLint texture6 = 0;
1956         GLint texture7 = 0;
1957         //if(state & RENDER_TEXTURE) != 0)
1958         {
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;
1967         }
1968
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);
1978         } else {
1979             setTextureState(current.m_texture, texture0);
1980         }
1981     }
1982
1983
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();
1988     }
1989
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();
1998     }
1999     current.m_colour = self.m_colour;
2000
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;
2007     }
2008
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;
2014     }
2015
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;
2021     }
2022
2023     current.m_state = state;
2024
2025     GlobalOpenGL_debugAssertNoErrors();
2026 }
2027
2028 void Renderables_flush(OpenGLStateBucket::Renderables &renderables, OpenGLState &current, unsigned int globalstate,
2029                        const Vector3 &viewer)
2030 {
2031     const Matrix4 *transform = 0;
2032     glPushMatrix();
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))) {
2036             count_transform();
2037             transform = (*i).m_transform;
2038             glPopMatrix();
2039             glPushMatrix();
2040             glMultMatrixf(reinterpret_cast<const float *>( transform ));
2041             glFrontFace(
2042                     ((current.m_state & RENDER_CULLFACE) != 0 && matrix4_handedness(*transform) == MATRIX4_RIGHTHANDED)
2043                     ? GL_CW : GL_CCW);
2044         }
2045
2046         count_prim();
2047
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;
2055
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);
2061
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);
2067
2068
2069                 AABB lightBounds((*i).m_light->aabb());
2070
2071                 Matrix4 world2light(g_matrix4_identity);
2072
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
2077                 }
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
2086                 }
2087
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");
2091             }
2092         }
2093
2094         (*i).m_renderable->render(current.m_state);
2095     }
2096     glPopMatrix();
2097     renderables.clear();
2098 }
2099
2100 void OpenGLStateBucket::render(OpenGLState &current, unsigned int globalstate, const Vector3 &viewer)
2101 {
2102     if ((globalstate & m_state.m_state & RENDER_SCREEN) != 0) {
2103         OpenGLState_apply(m_state, current, globalstate);
2104         debug_colour("screen fill");
2105
2106         glMatrixMode(GL_PROJECTION);
2107         glPushMatrix();
2108         glLoadMatrixf(reinterpret_cast<const float *>( &g_matrix4_identity ));
2109
2110         glMatrixMode(GL_MODELVIEW);
2111         glPushMatrix();
2112         glLoadMatrixf(reinterpret_cast<const float *>( &g_matrix4_identity ));
2113
2114         glBegin(GL_QUADS);
2115         glVertex3f(-1, -1, 0);
2116         glVertex3f(1, -1, 0);
2117         glVertex3f(1, 1, 0);
2118         glVertex3f(-1, 1, 0);
2119         glEnd();
2120
2121         glMatrixMode(GL_PROJECTION);
2122         glPopMatrix();
2123
2124         glMatrixMode(GL_MODELVIEW);
2125         glPopMatrix();
2126     } else if (!m_renderables.empty()) {
2127         OpenGLState_apply(m_state, current, globalstate);
2128         Renderables_flush(m_renderables, current, globalstate, viewer);
2129     }
2130 }
2131
2132
2133 class OpenGLStateMap : public OpenGLStateLibrary {
2134     typedef std::map<CopiedString, OpenGLState> States;
2135     States m_states;
2136 public:
2137     ~OpenGLStateMap()
2138     {
2139         ASSERT_MESSAGE(m_states.empty(), "OpenGLStateMap::~OpenGLStateMap: not empty");
2140     }
2141
2142     typedef States::iterator iterator;
2143
2144     iterator begin()
2145     {
2146         return m_states.begin();
2147     }
2148
2149     iterator end()
2150     {
2151         return m_states.end();
2152     }
2153
2154     void getDefaultState(OpenGLState &state) const
2155     {
2156         OpenGLState_constructDefault(state);
2157     }
2158
2159     void insert(const char *name, const OpenGLState &state)
2160     {
2161         bool inserted = m_states.insert(States::value_type(name, state)).second;
2162         ASSERT_MESSAGE(inserted, "OpenGLStateMap::insert: " << name << " already exists");
2163     }
2164
2165     void erase(const char *name)
2166     {
2167         std::size_t count = m_states.erase(name);
2168         ASSERT_MESSAGE(count == 1, "OpenGLStateMap::erase: " << name << " does not exist");
2169     }
2170
2171     iterator find(const char *name)
2172     {
2173         return m_states.find(name);
2174     }
2175 };
2176
2177 OpenGLStateMap *g_openglStates = 0;
2178
2179 inline GLenum convertBlendFactor(BlendFactor factor)
2180 {
2181     switch (factor) {
2182         case BLEND_ZERO:
2183             return GL_ZERO;
2184         case BLEND_ONE:
2185             return GL_ONE;
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;
2204     }
2205     return GL_ZERO;
2206 }
2207
2208 /// \todo Define special-case shaders in a data file.
2209 void OpenGLShader::construct(const char *name)
2210 {
2211     OpenGLState &state = appendDefaultPass();
2212     switch (name[0]) {
2213         case '(':
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 |
2217                             RENDER_DEPTHWRITE;
2218             state.m_sort = OpenGLState::eSortFullbright;
2219             break;
2220
2221         case '[':
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;
2227             break;
2228
2229         case '<':
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;
2237             break;
2238
2239         case '$': {
2240             OpenGLStateMap::iterator i = g_openglStates->find(name);
2241             if (i != g_openglStates->end()) {
2242                 state = (*i).second;
2243                 break;
2244             }
2245         }
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;
2263
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 |
2285                                 RENDER_DEPTHWRITE;
2286                 state.m_sort = OpenGLState::eSortHighlight;
2287                 state.m_depthfunc = GL_LEQUAL;
2288             } else if (string_equal(name + 1, "CAM_OVERLAY")) {
2289 #if 0
2290                                                                                                                                         state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
2291                         state.m_sort = OpenGLState::eSortOverlayFirst;
2292 #else
2293                 state.m_state =
2294                         RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OFFSETLINE;
2295                 state.m_sort = OpenGLState::eSortOverlayFirst + 1;
2296                 state.m_depthfunc = GL_LEQUAL;
2297
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 |
2304                                      RENDER_LINESTIPPLE;
2305                 hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
2306                 hiddenLine.m_depthfunc = GL_GREATER;
2307                 hiddenLine.m_linestipple_factor = 2;
2308 #endif
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 |
2335                                 RENDER_DEPTHWRITE;
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")) {
2349 #if 0
2350                                                                                                                                         state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
2351                         state.m_sort = OpenGLState::eSortOverlayFirst;
2352 #else
2353                 state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST |
2354                                 RENDER_OVERRIDE;
2355                 state.m_sort = OpenGLState::eSortGUI1;
2356                 state.m_depthfunc = GL_LEQUAL;
2357
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;
2363 #endif
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 |
2367                                 RENDER_OVERRIDE;
2368                 state.m_sort = OpenGLState::eSortGUI1;
2369                 state.m_depthfunc = GL_LEQUAL;
2370
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;
2383                 state.m_state =
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;
2396             } else {
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;
2405             }
2406             break;
2407         default:
2408             // construction from IShader
2409             m_shader = QERApp_Shader_ForName(name);
2410
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;
2420
2421                 if (g_ShaderCache->useShaderLanguage()) {
2422                     state.m_program = &g_depthFillGLSL;
2423                 } else {
2424                     state.m_program = &g_depthFillARB;
2425                 }
2426
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;
2431
2432                 bumpPass.m_state =
2433                         RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE |
2434                         RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
2435
2436                 if (g_ShaderCache->useShaderLanguage()) {
2437                     bumpPass.m_state |= RENDER_LIGHTING;
2438                     bumpPass.m_program = &g_bumpGLSL;
2439                 } else {
2440                     bumpPass.m_program = &g_bumpARB;
2441                 }
2442
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;
2447             } else {
2448                 state.m_texture = m_shader->getTexture()->texture_number;
2449
2450                 state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING |
2451                                 RENDER_SMOOTH;
2452                 if ((m_shader->getFlags() & QER_CULL) != 0) {
2453                     if (m_shader->getCull() == IShader::eCullBack) {
2454                         state.m_state |= RENDER_CULLFACE;
2455                     }
2456                 } else {
2457                     state.m_state |= RENDER_CULLFACE;
2458                 }
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;
2466                         case IShader::eEqual:
2467                             state.m_alphafunc = GL_EQUAL;
2468                         case IShader::eLess:
2469                             state.m_alphafunc = GL_LESS;
2470                         case IShader::eGreater:
2471                             state.m_alphafunc = GL_GREATER;
2472                         case IShader::eLEqual:
2473                             state.m_alphafunc = GL_LEQUAL;
2474                         case IShader::eGEqual:
2475                             state.m_alphafunc = GL_GEQUAL;
2476                     }
2477                 }
2478                 reinterpret_cast<Vector3 &>( state.m_colour ) = m_shader->getTexture()->color;
2479                 state.m_colour[3] = 1.0f;
2480
2481                 if ((m_shader->getFlags() & QER_TRANS) != 0) {
2482                     state.m_state |= RENDER_BLEND;
2483                     state.m_colour[3] = m_shader->getTrans();
2484                     state.m_sort = OpenGLState::eSortTranslucent;
2485                     BlendFunc blendFunc = m_shader->getBlendFunc();
2486                     state.m_blend_src = convertBlendFactor(blendFunc.m_src);
2487                     state.m_blend_dst = convertBlendFactor(blendFunc.m_dst);
2488                     if (state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA) {
2489                         state.m_state |= RENDER_DEPTHWRITE;
2490                     }
2491                 } else {
2492                     state.m_state |= RENDER_DEPTHWRITE;
2493                     state.m_sort = OpenGLState::eSortFullbright;
2494                 }
2495             }
2496     }
2497 }
2498
2499
2500 #include "modulesystem/singletonmodule.h"
2501 #include "modulesystem/moduleregistry.h"
2502
2503 class OpenGLStateLibraryAPI {
2504     OpenGLStateMap m_stateMap;
2505 public:
2506     typedef OpenGLStateLibrary Type;
2507
2508     STRING_CONSTANT(Name, "*");
2509
2510     OpenGLStateLibraryAPI()
2511     {
2512         g_openglStates = &m_stateMap;
2513     }
2514
2515     ~OpenGLStateLibraryAPI()
2516     {
2517         g_openglStates = 0;
2518     }
2519
2520     OpenGLStateLibrary *getTable()
2521     {
2522         return &m_stateMap;
2523     }
2524 };
2525
2526 typedef SingletonModule<OpenGLStateLibraryAPI> OpenGLStateLibraryModule;
2527 typedef Static<OpenGLStateLibraryModule> StaticOpenGLStateLibraryModule;
2528 StaticRegisterModule staticRegisterOpenGLStateLibrary(StaticOpenGLStateLibraryModule::instance());
2529
2530 class ShaderCacheDependencies
2531         : public GlobalShadersModuleRef, public GlobalTexturesModuleRef, public GlobalOpenGLStateLibraryModuleRef {
2532 public:
2533     ShaderCacheDependencies() :
2534             GlobalShadersModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("shaders"))
2535     {
2536     }
2537 };
2538
2539 class ShaderCacheAPI {
2540     ShaderCache *m_shaderCache;
2541 public:
2542     typedef ShaderCache Type;
2543
2544     STRING_CONSTANT(Name, "*");
2545
2546     ShaderCacheAPI()
2547     {
2548         ShaderCache_Construct();
2549
2550         m_shaderCache = GetShaderCache();
2551     }
2552
2553     ~ShaderCacheAPI()
2554     {
2555         ShaderCache_Destroy();
2556     }
2557
2558     ShaderCache *getTable()
2559     {
2560         return m_shaderCache;
2561     }
2562 };
2563
2564 typedef SingletonModule<ShaderCacheAPI, ShaderCacheDependencies> ShaderCacheModule;
2565 typedef Static<ShaderCacheModule> StaticShaderCacheModule;
2566 StaticRegisterModule staticRegisterShaderCache(StaticShaderCacheModule::instance());