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