1 #pragma once
2 
3 #include "irender.h"
4 #include "OpenGLStateManager.h"
5 #include "container/cache.h"
6 #include "container/hashfunc.h"
7 
8 class OpenGLShaderCache: public ShaderCache,
9 		public TexturesCacheObserver,
10 		public ModuleObserver,
11 		public render::OpenGLStateManager
12 {
13 		class CreateOpenGLShader
14 		{
15 				OpenGLShaderCache* m_cache;
16 			public:
17 				explicit CreateOpenGLShader (OpenGLShaderCache* cache = 0) :
m_cache(cache)18 					m_cache(cache)
19 				{
20 				}
construct(const std::string & name)21 				OpenGLShader* construct (const std::string& name)
22 				{
23 					OpenGLShader* shader = new OpenGLShader(*m_cache);
24 					if (m_cache->realised()) {
25 						shader->realise(name);
26 					}
27 					return shader;
28 				}
destroy(OpenGLShader * shader)29 				void destroy (OpenGLShader* shader)
30 				{
31 					if (m_cache->realised()) {
32 						shader->unrealise();
33 					}
34 					delete shader;
35 				}
36 		};
37 
38 		typedef HashedCache<std::string, OpenGLShader, HashString, std::equal_to<std::string>, CreateOpenGLShader>
39 				Shaders;
40 		Shaders m_shaders;
41 		std::size_t m_unrealised;
42 
43 		render::OpenGLStates _state_sorted;
44 
45 	public:
OpenGLShaderCache()46 		OpenGLShaderCache () :
47 			m_shaders(CreateOpenGLShader(this)), m_unrealised(3), // wait until shaders, gl-context and textures are realised before creating any render-states
48 					m_traverseRenderablesMutex(false)
49 		{
50 		}
~OpenGLShaderCache()51 		~OpenGLShaderCache ()
52 		{
53 			for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
54 				globalOutputStream() << "leaked shader: " << makeQuoted(i->key) << "\n";
55 			}
56 		}
57 
insertSortedState(const render::OpenGLStates::value_type & val)58 		void insertSortedState (const render::OpenGLStates::value_type& val)
59 		{
60 			_state_sorted.insert(val);
61 		}
62 
eraseSortedState(const render::OpenGLStates::key_type & key)63 		void eraseSortedState (const render::OpenGLStates::key_type& key)
64 		{
65 			_state_sorted.erase(key);
66 		}
67 
68 		/* Capture the given shader.
69 		 */
capture(const std::string & name)70 		Shader* capture (const std::string& name)
71 		{
72 			return m_shaders.capture(name).get();
73 		}
74 
75 		/* Release the given shader.
76 		 */
release(const std::string & name)77 		void release (const std::string& name)
78 		{
79 			m_shaders.release(name);
80 		}
81 
render(RenderStateFlags globalstate,const Matrix4 & modelview,const Matrix4 & projection,const Vector3 & viewer)82 		void render (RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection,
83 				const Vector3& viewer)
84 		{
85 			glMatrixMode(GL_PROJECTION);
86 			glLoadMatrixf(projection);
87 
88 			glMatrixMode(GL_MODELVIEW);
89 			glLoadMatrixf(modelview);
90 
91 			ASSERT_MESSAGE(realised(), "render states are not realised");
92 
93 			// global settings that are not set in renderstates
94 			glFrontFace(GL_CW);
95 			glCullFace(GL_BACK);
96 			glPolygonOffset(-1, 1);
97 			{
98 				const GLubyte pattern[132] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
99 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
100 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
101 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
102 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
103 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
104 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
105 						0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
106 						0x55, 0x55, 0x55, 0x55 };
107 				glPolygonStipple(pattern);
108 			}
109 			glEnableClientState(GL_VERTEX_ARRAY);
110 			glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
111 
112 			if (GlobalOpenGL().GL_1_3()) {
113 				glActiveTexture(GL_TEXTURE0);
114 				glClientActiveTexture(GL_TEXTURE0);
115 			}
116 
117 			if (globalstate & RENDER_TEXTURE_2D) {
118 				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
119 				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
120 			}
121 
122 			OpenGLState current;
123 			current.constructDefault();
124 			current.m_sort = OpenGLState::eSortFirst;
125 
126 			// default renderstate settings
127 			glLineStipple(current.m_linestipple_factor, current.m_linestipple_pattern);
128 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
129 			glDisable(GL_LIGHTING);
130 			glDisable(GL_TEXTURE_2D);
131 			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
132 			glDisableClientState(GL_COLOR_ARRAY);
133 			glDisableClientState(GL_NORMAL_ARRAY);
134 			glDisable(GL_BLEND);
135 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
136 			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
137 			glDisable(GL_CULL_FACE);
138 			glShadeModel(GL_FLAT);
139 			glDisable(GL_DEPTH_TEST);
140 			glDepthMask(GL_FALSE);
141 			glDisable(GL_ALPHA_TEST);
142 			glDisable(GL_LINE_STIPPLE);
143 			glDisable(GL_POLYGON_STIPPLE);
144 			glDisable(GL_POLYGON_OFFSET_LINE);
145 			glDisable(GL_POLYGON_OFFSET_FILL); // greebo: otherwise tiny gap lines between brushes are visible
146 
147 			glBindTexture(GL_TEXTURE_2D, 0);
148 			glColor4f(1, 1, 1, 1);
149 			glDepthFunc(GL_LESS);
150 			glAlphaFunc(GL_ALWAYS, 0);
151 			glLineWidth(1);
152 			glPointSize(1);
153 
154 			// render brushes and entities
155 			for (render::OpenGLStates::iterator i = _state_sorted.begin(); i != _state_sorted.end(); ++i) {
156 				(*i).second->render(current, globalstate, viewer);
157 			}
158 		}
realise()159 		void realise ()
160 		{
161 			if (--m_unrealised == 0) {
162 				for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
163 					if (!(*i).value.empty()) {
164 						(*i).value->realise(i->key);
165 					}
166 				}
167 			}
168 		}
unrealise()169 		void unrealise ()
170 		{
171 			if (++m_unrealised == 1) {
172 				for (Shaders::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {
173 					if (!(*i).value.empty()) {
174 						(*i).value->unrealise();
175 					}
176 				}
177 			}
178 		}
realised()179 		bool realised ()
180 		{
181 			return m_unrealised == 0;
182 		}
183 
184 		typedef std::set<const Renderable*> Renderables;
185 		Renderables m_renderables;
186 		mutable bool m_traverseRenderablesMutex;
187 
188 		// renderables
attachRenderable(const Renderable & renderable)189 		void attachRenderable (const Renderable& renderable)
190 		{
191 			ASSERT_MESSAGE(!m_traverseRenderablesMutex, "attaching renderable during traversal");
192 			ASSERT_MESSAGE(m_renderables.find(&renderable) == m_renderables.end(),
193 					"renderable could not be attached");
194 			m_renderables.insert(&renderable);
195 		}
detachRenderable(const Renderable & renderable)196 		void detachRenderable (const Renderable& renderable)
197 		{
198 			ASSERT_MESSAGE(!m_traverseRenderablesMutex, "detaching renderable during traversal");
199 			ASSERT_MESSAGE(m_renderables.find(&renderable) != m_renderables.end(),
200 					"renderable could not be detached");
201 			m_renderables.erase(&renderable);
202 		}
forEachRenderable(const RenderableCallback & callback)203 		void forEachRenderable (const RenderableCallback& callback) const
204 		{
205 			ASSERT_MESSAGE(!m_traverseRenderablesMutex, "for-each during traversal");
206 			m_traverseRenderablesMutex = true;
207 			for (Renderables::const_iterator i = m_renderables.begin(); i != m_renderables.end(); ++i) {
208 				callback(*(*i));
209 			}
210 			m_traverseRenderablesMutex = false;
211 		}
212 };
213