1 #include "OpenGLShader.h"
2 #include "OpenGLShaderPass.h"
3 #include "OpenGLStateLess.h"
4 #include "OpenGLStateManager.h"
5 
6 #include "ishadersystem.h"
7 #include "irender.h"
8 #include "ishader.h"
9 
10 #include "string/string.h"
11 #include "../../plugin.h"
12 
OpenGLShader(render::OpenGLStateManager & glStateManager)13 OpenGLShader::OpenGLShader (render::OpenGLStateManager& glStateManager) :
14 	m_shader(0), m_used(0), _glStateManager(glStateManager)
15 {
16 }
17 
~OpenGLShader()18 OpenGLShader::~OpenGLShader ()
19 {
20 }
21 
destroy()22 void OpenGLShader::destroy ()
23 {
24 	if (m_shader) {
25 		m_shader->DecRef();
26 	}
27 	m_shader = 0;
28 
29 	for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
30 		delete *i;
31 	}
32 	m_passes.clear();
33 }
34 
addRenderable(const OpenGLRenderable & renderable,const Matrix4 & modelview)35 void OpenGLShader::addRenderable (const OpenGLRenderable& renderable, const Matrix4& modelview)
36 {
37 	for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
38 		(*i)->addRenderable(renderable, modelview);
39 	}
40 }
41 
incrementUsed()42 void OpenGLShader::incrementUsed ()
43 {
44 	if (++m_used == 1 && m_shader != 0) {
45 		m_shader->setInUse(true);
46 	}
47 }
48 
decrementUsed()49 void OpenGLShader::decrementUsed ()
50 {
51 	if (--m_used == 0 && m_shader != 0) {
52 		m_shader->setInUse(false);
53 	}
54 }
55 
realised() const56 bool OpenGLShader::realised () const
57 {
58 	return m_shader != 0;
59 }
60 
attach(ModuleObserver & observer)61 void OpenGLShader::attach (ModuleObserver& observer)
62 {
63 	if (realised()) {
64 		observer.realise();
65 	}
66 	m_observers.attach(observer);
67 }
68 
detach(ModuleObserver & observer)69 void OpenGLShader::detach (ModuleObserver& observer)
70 {
71 	if (realised()) {
72 		observer.unrealise();
73 	}
74 	m_observers.detach(observer);
75 }
76 
realise(const std::string & name)77 void OpenGLShader::realise (const std::string& name)
78 {
79 	if (!name.empty())
80 		construct(name);
81 
82 	if (m_used != 0 && m_shader != 0) {
83 		m_shader->setInUse(true);
84 	}
85 
86 	for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
87 		_glStateManager.insertSortedState(render::OpenGLStates::value_type(&(*i)->getState(), *i));
88 	}
89 
90 	m_observers.realise();
91 }
92 
unrealise()93 void OpenGLShader::unrealise ()
94 {
95 	m_observers.unrealise();
96 
97 	for (Passes::iterator i = m_passes.begin(); i != m_passes.end(); ++i) {
98 		_glStateManager.eraseSortedState(&(*i)->getState());
99 	}
100 
101 	destroy();
102 }
103 
getTexture() const104 GLTexture& OpenGLShader::getTexture () const
105 {
106 	ASSERT_NOTNULL(m_shader);
107 	return *m_shader->getTexture();
108 }
109 
getFlags() const110 unsigned int OpenGLShader::getFlags () const
111 {
112 	ASSERT_NOTNULL(m_shader);
113 	return m_shader->getFlags();
114 }
115 
getShader() const116 IShader& OpenGLShader::getShader () const
117 {
118 	ASSERT_NOTNULL(m_shader);
119 	return *m_shader;
120 }
121 
appendDefaultPass()122 OpenGLState& OpenGLShader::appendDefaultPass ()
123 {
124 	m_passes.push_back(new OpenGLShaderPass);
125 	OpenGLState& state = m_passes.back()->getState();
126 	state.constructDefault();
127 	return state;
128 }
129 
convertBlendFactor(BlendFactor factor)130 GLenum OpenGLShader::convertBlendFactor (BlendFactor factor)
131 {
132 	switch (factor) {
133 	case BLEND_ZERO:
134 		return GL_ZERO;
135 	case BLEND_ONE:
136 		return GL_ONE;
137 	case BLEND_SRC_COLOUR:
138 		return GL_SRC_COLOR;
139 	case BLEND_ONE_MINUS_SRC_COLOUR:
140 		return GL_ONE_MINUS_SRC_COLOR;
141 	case BLEND_SRC_ALPHA:
142 		return GL_SRC_ALPHA;
143 	case BLEND_ONE_MINUS_SRC_ALPHA:
144 		return GL_ONE_MINUS_SRC_ALPHA;
145 	case BLEND_DST_COLOUR:
146 		return GL_DST_COLOR;
147 	case BLEND_ONE_MINUS_DST_COLOUR:
148 		return GL_ONE_MINUS_DST_COLOR;
149 	case BLEND_DST_ALPHA:
150 		return GL_DST_ALPHA;
151 	case BLEND_ONE_MINUS_DST_ALPHA:
152 		return GL_ONE_MINUS_DST_ALPHA;
153 	case BLEND_SRC_ALPHA_SATURATE:
154 		return GL_SRC_ALPHA_SATURATE;
155 	}
156 	return GL_ZERO;
157 }
158 
159 // Append a blend (non-interaction) layer
appendBlendLayer(const ShaderLayer & layer)160 void OpenGLShader::appendBlendLayer (const ShaderLayer& layer)
161 {
162 	GLTexture* layerTex = layer.getTexture();
163 
164 	OpenGLState& state = appendDefaultPass();
165 	state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_COLOURCHANGE | RENDER_TEXTURE_2D;
166 	state.m_depthfunc = GL_LEQUAL;
167 
168 	// Set the texture
169 	state.m_texture = layerTex->texture_number;
170 
171 	// Get the blend function
172 	BlendFunc blendFunc = layer.getBlendFunc();
173 	state.m_blend_src = convertBlendFactor(blendFunc.m_src);
174 	state.m_blend_dst = convertBlendFactor(blendFunc.m_dst);
175 
176 	// Alpha-tested stages or one-over-zero blends should use the depth buffer
177 	if (state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA || (state.m_blend_src == GL_ONE
178 			&& state.m_blend_dst == GL_ZERO)) {
179 		state.m_state |= RENDER_DEPTHWRITE;
180 	}
181 
182 	// Colour modulation
183 	state.m_colour = Vector4(layer.getColour(), 1.0f);
184 
185 	state.m_sort = OpenGLState::eSortOverlayFirst;
186 
187 	// Polygon offset
188 	state.m_polygonOffset = layer.getPolygonOffset();
189 }
190 
visitShaderLayers(const ShaderLayer & layer)191 void OpenGLShader::visitShaderLayers (const ShaderLayer& layer)
192 {
193 	if (layer.getType() == ShaderLayer::BLEND)
194 		appendBlendLayer(layer);
195 }
196 
197 /// \todo Define special-case shaders in a data file.
construct(const std::string & name)198 void OpenGLShader::construct (const std::string& name)
199 {
200 	static Vector4 highLightColour(1, 0, 0, 0.3);
201 
202 	// Check the first character of the name to see if this is a special built-in shader
203 	switch (name[0]) {
204 	case '(': {
205 		// fill shader
206 		OpenGLState& state = appendDefaultPass();
207 		sscanf(name.c_str(), "(%g %g %g)", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
208 		state.m_colour[3] = 1.0f;
209 		state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE
210 				| RENDER_DEPTHWRITE;
211 		state.m_sort = OpenGLState::eSortFullbright;
212 		break;
213 	}
214 
215 	case '[': {
216 		OpenGLState& state = appendDefaultPass();
217 		sscanf(name.c_str(), "[%g %g %g]", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
218 		state.m_colour[3] = 0.5f;
219 		state.m_state = RENDER_FILL | RENDER_LIGHTING | RENDER_DEPTHTEST | RENDER_CULLFACE | RENDER_COLOURWRITE
220 				| RENDER_DEPTHWRITE | RENDER_BLEND;
221 		state.m_sort = OpenGLState::eSortTranslucent;
222 		break;
223 	}
224 
225 	case '<': {
226 		// wireframe shader
227 		OpenGLState& state = appendDefaultPass();
228 		sscanf(name.c_str(), "<%g %g %g>", &state.m_colour[0], &state.m_colour[1], &state.m_colour[2]);
229 		state.m_colour[3] = 1;
230 		state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
231 		state.m_sort = OpenGLState::eSortFullbright;
232 		state.m_depthfunc = GL_LESS;
233 		state.m_linewidth = 1;
234 		state.m_pointsize = 1;
235 		break;
236 	}
237 
238 	case '$': {
239 		OpenGLState& state = appendDefaultPass();
240 
241 		if (name == "$POINT") {
242 			state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
243 			state.m_sort = OpenGLState::eSortControlFirst;
244 			state.m_pointsize = 4;
245 		} else if (name == "$SELPOINT") {
246 			state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
247 			state.m_sort = OpenGLState::eSortControlFirst + 1;
248 			state.m_pointsize = 4;
249 		} else if (name == "$PIVOT") {
250 			state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE;
251 			state.m_sort = OpenGLState::eSortGUI1;
252 			state.m_linewidth = 2;
253 			state.m_depthfunc = GL_LEQUAL;
254 
255 			OpenGLState& hiddenLine = appendDefaultPass();
256 			hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
257 			hiddenLine.m_sort = OpenGLState::eSortGUI0;
258 			hiddenLine.m_linewidth = 2;
259 			hiddenLine.m_depthfunc = GL_GREATER;
260 		} else if (name == "$WIREFRAME") {
261 			state.m_state = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
262 			state.m_sort = OpenGLState::eSortFullbright;
263 		} else if (name == "$CAM_HIGHLIGHT") {
264 			state.m_colour = highLightColour;
265 			state.m_state = RENDER_FILL | RENDER_DEPTHTEST | RENDER_CULLFACE
266 					| RENDER_BLEND | RENDER_COLOURWRITE;
267 			state.m_sort = OpenGLState::eSortHighlight;
268 			state.m_depthfunc = GL_LEQUAL;
269 		} else if (name == "$CAM_OVERLAY") {
270 			state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE
271 					| RENDER_OFFSETLINE;
272 			state.m_sort = OpenGLState::eSortOverlayFirst + 1;
273 			state.m_depthfunc = GL_LEQUAL;
274 
275 			OpenGLState& hiddenLine = appendDefaultPass();
276 			hiddenLine.m_colour = Vector4(0.75, 0.75, 0.75, 1);
277 			hiddenLine.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_OFFSETLINE
278 					| RENDER_LINESTIPPLE;
279 			hiddenLine.m_sort = OpenGLState::eSortOverlayFirst;
280 			hiddenLine.m_depthfunc = GL_GREATER;
281 			hiddenLine.m_linestipple_factor = 2;
282 		} else if (name == "$XY_OVERLAY") {
283 			Vector3 colorSelBrushes = ColourSchemes().getColourVector3("selected_brush");
284 			state.m_colour = Vector4(colorSelBrushes, 1);
285 			state.m_state = RENDER_COLOURWRITE | RENDER_LINESTIPPLE;
286 			state.m_sort = OpenGLState::eSortOverlayFirst;
287 			state.m_linewidth = 2;
288 			state.m_linestipple_factor = 3;
289 		} else if (name == "$DEBUG_CLIPPED") {
290 			state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
291 			state.m_sort = OpenGLState::eSortLast;
292 		} else if (name == "$SPHERE") {
293 			state.m_colour =  Vector4(.05f, .05f, .05f, 1);
294 			state.m_state = RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_BLEND | RENDER_FILL;
295 			state.m_blend_src = GL_ONE;
296 			state.m_blend_dst = GL_ONE;
297 			state.m_sort = OpenGLState::eSortTranslucent;
298 		} else if (name == "$WIRE_OVERLAY") {
299 #if 0
300 			state._visStack = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
301 			state.m_sort = OpenGLState::eSortOverlayFirst;
302 #else
303 			state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST
304 					| RENDER_OVERRIDE;
305 			state.m_sort = OpenGLState::eSortGUI1;
306 			state.m_depthfunc = GL_LEQUAL;
307 
308 			OpenGLState& hiddenLine = appendDefaultPass();
309 			hiddenLine.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST
310 					| RENDER_OVERRIDE | RENDER_LINESTIPPLE;
311 			hiddenLine.m_sort = OpenGLState::eSortGUI0;
312 			hiddenLine.m_depthfunc = GL_GREATER;
313 #endif
314 		} else if (name == "$FLATSHADE_OVERLAY") {
315 			state.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY
316 					| RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE;
317 			state.m_sort = OpenGLState::eSortGUI1;
318 			state.m_depthfunc = GL_LEQUAL;
319 
320 			OpenGLState& hiddenLine = appendDefaultPass();
321 			hiddenLine.m_state = RENDER_CULLFACE | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED | RENDER_COLOURARRAY
322 					| RENDER_FILL | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OVERRIDE
323 					| RENDER_POLYGONSTIPPLE;
324 			hiddenLine.m_sort = OpenGLState::eSortGUI0;
325 			hiddenLine.m_depthfunc = GL_GREATER;
326 		} else if (name == "$CLIPPER_OVERLAY") {
327 			Vector3 colorClipper = ColourSchemes().getColourVector3("clipper");
328 			state.m_colour = Vector4(colorClipper, 1);
329 			state.m_state = RENDER_CULLFACE | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_FILL
330 					| RENDER_POLYGONSTIPPLE;
331 			state.m_sort = OpenGLState::eSortOverlayFirst;
332 		} else {
333 			// default to something recognisable.. =)
334 			ERROR_MESSAGE("hardcoded renderstate not found");
335 			state.m_colour = Vector4(1, 0, 1, 1);
336 			state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
337 			state.m_sort = OpenGLState::eSortFirst;
338 		}
339 		break;
340 	} // case '$'
341 
342 	default: {
343 		// This is not a hard-coded shader, construct from the shader system
344 		constructNormalShader(name);
345 	}
346 
347 	} // switch
348 }
349 
isTransparent(const std::string & name)350 bool OpenGLShader::isTransparent (const std::string& name)
351 {
352 	return string::contains(name, "tex_common/");
353 }
354 
constructNormalShader(const std::string & name)355 void OpenGLShader::constructNormalShader (const std::string& name)
356 {
357 	// construction from IShader
358 	m_shader = GlobalShaderSystem().getShaderForName(name);
359 
360 	OpenGLState& state = appendDefaultPass();
361 
362 	state.m_texture = m_shader->getTexture()->texture_number;
363 
364 	state.m_state = RENDER_FILL | RENDER_TEXTURE_2D | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING
365 			| RENDER_SMOOTH;
366 	state.m_state |= RENDER_CULLFACE;
367 	if ((m_shader->getFlags() & QER_ALPHATEST) != 0) {
368 		state.m_state |= RENDER_ALPHATEST;
369 		state.m_colour[3] = 0.25;
370 		IShader::EAlphaFunc alphafunc;
371 		m_shader->getAlphaFunc(&alphafunc, &state.m_alpharef);
372 		switch (alphafunc) {
373 		case IShader::eAlways:
374 			state.m_alphafunc = GL_ALWAYS;
375 			break;
376 		case IShader::eEqual:
377 			state.m_alphafunc = GL_EQUAL;
378 			break;
379 		case IShader::eLess:
380 			state.m_alphafunc = GL_LESS;
381 			break;
382 		case IShader::eGreater:
383 			state.m_alphafunc = GL_GREATER;
384 			break;
385 		case IShader::eLEqual:
386 			state.m_alphafunc = GL_LEQUAL;
387 			break;
388 		case IShader::eGEqual:
389 			state.m_alphafunc = GL_GEQUAL;
390 			break;
391 		}
392 	}
393 
394 	state.m_colour = Vector4(m_shader->getTexture()->color, 1.0);
395 
396 	if (isTransparent(m_shader->getName())) {
397 		state.m_state |= RENDER_BLEND;
398 		state.m_state |= RENDER_DEPTHWRITE;
399 		state.m_colour = Vector4(1.0, 1.0, 1.0, 0.4);
400 		state.m_sort = OpenGLState::eSortTranslucent;
401 	} else if ((m_shader->getFlags() & QER_TRANS) != 0) {
402 		state.m_state |= RENDER_BLEND;
403 		state.m_colour[3] = m_shader->getTrans();
404 		BlendFunc blendFunc = m_shader->getBlendFunc();
405 		state.m_blend_src = convertBlendFactor(blendFunc.m_src);
406 		state.m_blend_dst = convertBlendFactor(blendFunc.m_dst);
407 		if (state.m_blend_src == GL_SRC_ALPHA || state.m_blend_dst == GL_SRC_ALPHA) {
408 			state.m_state |= RENDER_DEPTHWRITE;
409 		}
410 		state.m_sort = OpenGLState::eSortTranslucent;
411 	} else if (m_shader->getTexture()->hasAlpha) {
412 		state.m_state |= RENDER_BLEND;
413 		state.m_state |= RENDER_DEPTHWRITE;
414 		state.m_sort = OpenGLState::eSortTranslucent;
415 	} else {
416 		state.m_state |= RENDER_DEPTHWRITE;
417 		state.m_sort = OpenGLState::eSortFullbright;
418 	}
419 
420 	m_shader->forEachLayer(ShaderLayerVisitor(*this));
421 }
422