1 /**
2 * Copyright (c) 2006-2016 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21 // LOVE
22 #include "common/config.h"
23
24 #include "Shader.h"
25 #include "Canvas.h"
26
27 // C++
28 #include <algorithm>
29 #include <limits>
30
31 namespace love
32 {
33 namespace graphics
34 {
35 namespace opengl
36 {
37
38 namespace
39 {
40 // temporarily attaches a shader program (for setting uniforms, etc)
41 // reattaches the originally active program when destroyed
42 struct TemporaryAttacher
43 {
TemporaryAttacherlove::graphics::opengl::__anonfe70ebfb0111::TemporaryAttacher44 TemporaryAttacher(Shader *shader)
45 : curShader(shader)
46 , prevShader(Shader::current)
47 {
48 curShader->attach(true);
49 }
50
~TemporaryAttacherlove::graphics::opengl::__anonfe70ebfb0111::TemporaryAttacher51 ~TemporaryAttacher()
52 {
53 if (prevShader != nullptr)
54 prevShader->attach();
55 else
56 curShader->detach();
57 }
58
59 Shader *curShader;
60 Shader *prevShader;
61 };
62 } // anonymous namespace
63
64
65 Shader *Shader::current = nullptr;
66 Shader *Shader::defaultShader = nullptr;
67 Shader *Shader::defaultVideoShader = nullptr;
68
69 Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
70 Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
71
72 std::vector<int> Shader::textureCounters;
73
Shader(const ShaderSource & source)74 Shader::Shader(const ShaderSource &source)
75 : shaderSource(source)
76 , program(0)
77 , builtinUniforms()
78 , builtinAttributes()
79 , lastCanvas((Canvas *) -1)
80 , lastViewport()
81 , lastPointSize(0.0f)
82 , videoTextureUnits()
83 {
84 if (source.vertex.empty() && source.pixel.empty())
85 throw love::Exception("Cannot create shader: no source code!");
86
87 // initialize global texture id counters if needed
88 if ((int) textureCounters.size() < gl.getMaxTextureUnits() - 1)
89 textureCounters.resize(gl.getMaxTextureUnits() - 1, 0);
90
91 // load shader source and create program object
92 loadVolatile();
93 }
94
~Shader()95 Shader::~Shader()
96 {
97 if (current == this)
98 detach();
99
100 for (const auto &retainable : boundRetainables)
101 retainable.second->release();
102
103 boundRetainables.clear();
104
105 unloadVolatile();
106 }
107
compileCode(ShaderStage stage,const std::string & code)108 GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
109 {
110 GLenum glstage;
111 const char *typestr;
112
113 if (!stageNames.find(stage, typestr))
114 typestr = "";
115
116 switch (stage)
117 {
118 case STAGE_VERTEX:
119 glstage = GL_VERTEX_SHADER;
120 break;
121 case STAGE_PIXEL:
122 glstage = GL_FRAGMENT_SHADER;
123 break;
124 default:
125 throw love::Exception("Cannot create shader object: unknown shader type.");
126 break;
127 }
128
129 GLuint shaderid = glCreateShader(glstage);
130
131 if (shaderid == 0)
132 {
133 if (glGetError() == GL_INVALID_ENUM)
134 throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
135 else
136 throw love::Exception("Cannot create %s shader object.", typestr);
137 }
138
139 const char *src = code.c_str();
140 GLint srclen = (GLint) code.length();
141 glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen);
142
143 glCompileShader(shaderid);
144
145 GLint infologlen;
146 glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
147
148 // Get any warnings the shader compiler may have produced.
149 if (infologlen > 0)
150 {
151 GLchar *infolog = new GLchar[infologlen];
152 glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog);
153
154 // Save any warnings for later querying.
155 shaderWarnings[stage] = infolog;
156
157 delete[] infolog;
158 }
159
160 GLint status;
161 glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
162
163 if (status == GL_FALSE)
164 {
165 glDeleteShader(shaderid);
166 throw love::Exception("Cannot compile %s shader code:\n%s",
167 typestr, shaderWarnings[stage].c_str());
168 }
169
170 return shaderid;
171 }
172
mapActiveUniforms()173 void Shader::mapActiveUniforms()
174 {
175 // Built-in uniform locations default to -1 (nonexistant.)
176 for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
177 builtinUniforms[i] = -1;
178
179 uniforms.clear();
180
181 GLint activeprogram = 0;
182 glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
183
184 gl.useProgram(program);
185
186 GLint numuniforms;
187 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numuniforms);
188
189 GLchar cname[256];
190 const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
191
192 for (int i = 0; i < numuniforms; i++)
193 {
194 GLsizei namelen = 0;
195 GLenum gltype = 0;
196 UniformInfo u = {};
197
198 glGetActiveUniform(program, (GLuint) i, bufsize, &namelen, &u.count, &gltype, cname);
199
200 u.name = std::string(cname, (size_t) namelen);
201 u.location = glGetUniformLocation(program, u.name.c_str());
202 u.baseType = getUniformBaseType(gltype);
203 u.components = getUniformTypeSize(gltype);
204
205 // Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to
206 // do this themselves, but some Android devices (galaxy tab 3 and 4)
207 // don't seem to do it...
208 if (u.baseType == UNIFORM_SAMPLER)
209 glUniform1i(u.location, 0);
210
211 // glGetActiveUniform appends "[0]" to the end of array uniform names...
212 if (u.name.length() > 3)
213 {
214 size_t findpos = u.name.find("[0]");
215 if (findpos != std::string::npos && findpos == u.name.length() - 3)
216 u.name.erase(u.name.length() - 3);
217 }
218
219 // If this is a built-in (LOVE-created) uniform, store the location.
220 BuiltinUniform builtin;
221 if (builtinNames.find(u.name.c_str(), builtin))
222 builtinUniforms[int(builtin)] = u.location;
223
224 if (u.location != -1)
225 uniforms[u.name] = u;
226 }
227
228 gl.useProgram(activeprogram);
229 }
230
loadVolatile()231 bool Shader::loadVolatile()
232 {
233 OpenGL::TempDebugGroup debuggroup("Shader load");
234
235 // Recreating the shader program will invalidate uniforms that rely on these.
236 lastCanvas = (Canvas *) -1;
237 lastViewport = OpenGL::Viewport();
238
239 lastPointSize = -1.0f;
240
241 // Invalidate the cached matrices by setting some elements to NaN.
242 float nan = std::numeric_limits<float>::quiet_NaN();
243 lastProjectionMatrix.setTranslation(nan, nan);
244 lastTransformMatrix.setTranslation(nan, nan);
245
246 for (int i = 0; i < 3; i++)
247 videoTextureUnits[i] = 0;
248
249 // zero out active texture list
250 activeTexUnits.clear();
251 activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
252
253 std::vector<GLuint> shaderids;
254
255 bool gammacorrect = graphics::isGammaCorrect();
256 const ShaderSource *defaults = &defaultCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
257 if (GLAD_ES_VERSION_2_0)
258 defaults = &defaultCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
259
260 // The shader program must have both vertex and pixel shader stages.
261 const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
262 const std::string &pixelcode = shaderSource.pixel.empty() ? defaults->pixel : shaderSource.pixel;
263
264 try
265 {
266 shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode));
267 shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode));
268 }
269 catch (love::Exception &)
270 {
271 for (GLuint id : shaderids)
272 glDeleteShader(id);
273 throw;
274 }
275
276 program = glCreateProgram();
277
278 if (program == 0)
279 {
280 for (GLuint id : shaderids)
281 glDeleteShader(id);
282 throw love::Exception("Cannot create shader program object.");
283 }
284
285 for (GLuint id : shaderids)
286 glAttachShader(program, id);
287
288 // Bind generic vertex attribute indices to names in the shader.
289 for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
290 {
291 const char *name = nullptr;
292 if (attribNames.find((VertexAttribID) i, name))
293 glBindAttribLocation(program, i, (const GLchar *) name);
294 }
295
296 glLinkProgram(program);
297
298 // Flag shaders for auto-deletion when the program object is deleted.
299 for (GLuint id : shaderids)
300 glDeleteShader(id);
301
302 GLint status;
303 glGetProgramiv(program, GL_LINK_STATUS, &status);
304
305 if (status == GL_FALSE)
306 {
307 std::string warnings = getProgramWarnings();
308 glDeleteProgram(program);
309 program = 0;
310 throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
311 }
312
313 // Get all active uniform variables in this shader from OpenGL.
314 mapActiveUniforms();
315
316 for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
317 {
318 const char *name = nullptr;
319 if (attribNames.find(VertexAttribID(i), name))
320 builtinAttributes[i] = glGetAttribLocation(program, name);
321 else
322 builtinAttributes[i] = -1;
323 }
324
325 if (current == this)
326 {
327 // make sure glUseProgram gets called.
328 current = nullptr;
329 attach();
330 checkSetBuiltinUniforms();
331 }
332
333 return true;
334 }
335
unloadVolatile()336 void Shader::unloadVolatile()
337 {
338 if (current == this)
339 gl.useProgram(0);
340
341 if (program != 0)
342 {
343 glDeleteProgram(program);
344 program = 0;
345 }
346
347 // decrement global texture id counters for texture units which had textures bound from this shader
348 for (size_t i = 0; i < activeTexUnits.size(); ++i)
349 {
350 if (activeTexUnits[i] > 0)
351 textureCounters[i] = std::max(textureCounters[i] - 1, 0);
352 }
353
354 // active texture list is probably invalid, clear it
355 activeTexUnits.clear();
356 activeTexUnits.resize(gl.getMaxTextureUnits() - 1, 0);
357
358 attributes.clear();
359
360 // same with uniform location list
361 uniforms.clear();
362
363 // And the locations of any built-in uniform variables.
364 for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
365 builtinUniforms[i] = -1;
366
367 shaderWarnings.clear();
368 }
369
getProgramWarnings() const370 std::string Shader::getProgramWarnings() const
371 {
372 GLint strsize, nullpos;
373 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strsize);
374
375 if (strsize == 0)
376 return "";
377
378 char *tempstr = new char[strsize];
379 // be extra sure that the error string will be 0-terminated
380 memset(tempstr, '\0', strsize);
381 glGetProgramInfoLog(program, strsize, &nullpos, tempstr);
382 tempstr[nullpos] = '\0';
383
384 std::string warnings(tempstr);
385 delete[] tempstr;
386
387 return warnings;
388 }
389
getWarnings() const390 std::string Shader::getWarnings() const
391 {
392 std::string warnings;
393 const char *stagestr;
394
395 // Get the individual shader stage warnings
396 for (const auto &warning : shaderWarnings)
397 {
398 if (stageNames.find(warning.first, stagestr))
399 warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
400 }
401
402 warnings += getProgramWarnings();
403
404 return warnings;
405 }
406
attach(bool temporary)407 void Shader::attach(bool temporary)
408 {
409 if (current != this)
410 {
411 gl.useProgram(program);
412 current = this;
413 // retain/release happens in Graphics::setShader.
414
415 if (!temporary)
416 {
417 // make sure all sent textures are properly bound to their respective texture units
418 // note: list potentially contains texture ids of deleted/invalid textures!
419 for (size_t i = 0; i < activeTexUnits.size(); ++i)
420 {
421 if (activeTexUnits[i] > 0)
422 gl.bindTextureToUnit(activeTexUnits[i], i + 1, false);
423 }
424
425 // We always want to use texture unit 0 for everyhing else.
426 gl.setTextureUnit(0);
427 }
428 }
429 }
430
detach()431 void Shader::detach()
432 {
433 if (defaultShader)
434 {
435 if (current != defaultShader)
436 defaultShader->attach();
437
438 return;
439 }
440
441 if (current != nullptr)
442 gl.useProgram(0);
443
444 current = nullptr;
445 }
446
getUniformInfo(const std::string & name) const447 const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
448 {
449 const auto it = uniforms.find(name);
450
451 if (it == uniforms.end())
452 return nullptr;
453
454 return &(it->second);
455 }
456
sendInts(const UniformInfo * info,const int * vec,int count)457 void Shader::sendInts(const UniformInfo *info, const int *vec, int count)
458 {
459 if (info->baseType != UNIFORM_INT && info->baseType != UNIFORM_BOOL)
460 return;
461
462 TemporaryAttacher attacher(this);
463
464 int location = info->location;
465
466 switch (info->components)
467 {
468 case 4:
469 glUniform4iv(location, count, vec);
470 break;
471 case 3:
472 glUniform3iv(location, count, vec);
473 break;
474 case 2:
475 glUniform2iv(location, count, vec);
476 break;
477 case 1:
478 default:
479 glUniform1iv(location, count, vec);
480 break;
481 }
482 }
483
sendFloats(const UniformInfo * info,const float * vec,int count)484 void Shader::sendFloats(const UniformInfo *info, const float *vec, int count)
485 {
486 if (info->baseType != UNIFORM_FLOAT && info->baseType != UNIFORM_BOOL)
487 return;
488
489 TemporaryAttacher attacher(this);
490
491 int location = info->location;
492
493 switch (info->components)
494 {
495 case 4:
496 glUniform4fv(location, count, vec);
497 break;
498 case 3:
499 glUniform3fv(location, count, vec);
500 break;
501 case 2:
502 glUniform2fv(location, count, vec);
503 break;
504 case 1:
505 default:
506 glUniform1fv(location, count, vec);
507 break;
508 }
509 }
510
sendMatrices(const UniformInfo * info,const float * m,int count)511 void Shader::sendMatrices(const UniformInfo *info, const float *m, int count)
512 {
513 if (info->baseType != UNIFORM_MATRIX)
514 return;
515
516 TemporaryAttacher attacher(this);
517
518 int location = info->location;
519
520 switch (info->components)
521 {
522 case 4:
523 glUniformMatrix4fv(location, count, GL_FALSE, m);
524 break;
525 case 3:
526 glUniformMatrix3fv(location, count, GL_FALSE, m);
527 break;
528 case 2:
529 default:
530 glUniformMatrix2fv(location, count, GL_FALSE, m);
531 break;
532 }
533 }
534
sendTexture(const UniformInfo * info,Texture * texture)535 void Shader::sendTexture(const UniformInfo *info, Texture *texture)
536 {
537 if (info->baseType != UNIFORM_SAMPLER)
538 return;
539
540 GLuint gltex = *(GLuint *) texture->getHandle();
541
542 TemporaryAttacher attacher(this);
543
544 int texunit = getTextureUnit(info->name);
545
546 // bind texture to assigned texture unit and send uniform to shader program
547 gl.bindTextureToUnit(gltex, texunit, true);
548
549 glUniform1i(info->location, texunit);
550
551 // increment global shader texture id counter for this texture unit, if we haven't already
552 if (activeTexUnits[texunit-1] == 0)
553 ++textureCounters[texunit-1];
554
555 // store texture id so it can be re-bound to the proper texture unit later
556 activeTexUnits[texunit-1] = gltex;
557
558 retainObject(info->name, texture);
559 }
560
retainObject(const std::string & name,Object * object)561 void Shader::retainObject(const std::string &name, Object *object)
562 {
563 object->retain();
564
565 auto it = boundRetainables.find(name);
566 if (it != boundRetainables.end())
567 it->second->release();
568
569 boundRetainables[name] = object;
570 }
571
getTextureUnit(const std::string & name)572 int Shader::getTextureUnit(const std::string &name)
573 {
574 auto it = texUnitPool.find(name);
575
576 if (it != texUnitPool.end())
577 return it->second;
578
579 int texunit = 1;
580
581 // prefer texture units which are unused by all other shaders
582 auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0);
583
584 if (freeunit_it != textureCounters.end())
585 {
586 // we don't want to use unit 0
587 texunit = (int) std::distance(textureCounters.begin(), freeunit_it) + 1;
588 }
589 else
590 {
591 // no completely unused texture units exist, try to use next free slot in our own list
592 auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0);
593
594 if (nextunit_it == activeTexUnits.end())
595 throw love::Exception("No more texture units available for shader.");
596
597 // we don't want to use unit 0
598 texunit = (int) std::distance(activeTexUnits.begin(), nextunit_it) + 1;
599 }
600
601 texUnitPool[name] = texunit;
602 return texunit;
603 }
604
getExternVariable(const std::string & name,int & components,int & count)605 Shader::UniformType Shader::getExternVariable(const std::string &name, int &components, int &count)
606 {
607 auto it = uniforms.find(name);
608
609 if (it == uniforms.end())
610 {
611 components = 0;
612 count = 0;
613 return UNIFORM_UNKNOWN;
614 }
615
616 components = it->second.components;
617 count = (int) it->second.count;
618
619 // Legacy support. This whole function is gone in 0.11 anyway.
620 if (it->second.baseType == UNIFORM_MATRIX)
621 return UNIFORM_FLOAT;
622 return it->second.baseType;
623 }
624
getAttribLocation(const std::string & name)625 GLint Shader::getAttribLocation(const std::string &name)
626 {
627 auto it = attributes.find(name);
628 if (it != attributes.end())
629 return it->second;
630
631 GLint location = glGetAttribLocation(program, name.c_str());
632
633 attributes[name] = location;
634 return location;
635 }
636
hasVertexAttrib(VertexAttribID attrib) const637 bool Shader::hasVertexAttrib(VertexAttribID attrib) const
638 {
639 return builtinAttributes[int(attrib)] != -1;
640 }
641
setVideoTextures(GLuint ytexture,GLuint cbtexture,GLuint crtexture)642 void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
643 {
644 TemporaryAttacher attacher(this);
645
646 // Set up the texture units that will be used by the shader to sample from
647 // the textures, if they haven't been set up yet.
648 if (videoTextureUnits[0] == 0)
649 {
650 const GLint locs[3] = {
651 builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
652 builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
653 builtinUniforms[BUILTIN_VIDEO_CR_CHANNEL]
654 };
655
656 const char *names[3] = {nullptr, nullptr, nullptr};
657 builtinNames.find(BUILTIN_VIDEO_Y_CHANNEL, names[0]);
658 builtinNames.find(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
659 builtinNames.find(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
660
661 for (int i = 0; i < 3; i++)
662 {
663 if (locs[i] >= 0 && names[i] != nullptr)
664 {
665 videoTextureUnits[i] = getTextureUnit(names[i]);
666
667 // Increment global shader texture id counter for this texture
668 // unit, if we haven't already.
669 if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
670 ++textureCounters[videoTextureUnits[i] - 1];
671
672 glUniform1i(locs[i], videoTextureUnits[i]);
673 }
674 }
675 }
676
677 const GLuint textures[3] = {ytexture, cbtexture, crtexture};
678
679 // Bind the textures to their respective texture units.
680 for (int i = 0; i < 3; i++)
681 {
682 if (videoTextureUnits[i] != 0)
683 {
684 // Store texture id so it can be re-bound later.
685 activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
686 gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
687 }
688 }
689
690 gl.setTextureUnit(0);
691 }
692
checkSetScreenParams()693 void Shader::checkSetScreenParams()
694 {
695 OpenGL::Viewport view = gl.getViewport();
696
697 if (view == lastViewport && lastCanvas == Canvas::current)
698 return;
699
700 // In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
701 // This lets us flip pixcoord.y when needed, to be consistent (drawing with
702 // no Canvas active makes the y-values for pixel coordinates flipped.)
703 GLfloat params[] = {
704 (GLfloat) view.w, (GLfloat) view.h,
705 0.0f, 0.0f,
706 };
707
708 if (Canvas::current != nullptr)
709 {
710 // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
711 params[2] = 1.0f;
712 params[3] = 0.0f;
713 }
714 else
715 {
716 // gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
717 // pixcoord.y = gl_FragCoord.y * -1.0 + height.
718 params[2] = -1.0f;
719 params[3] = (GLfloat) view.h;
720 }
721
722 GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
723
724 if (location >= 0)
725 {
726 TemporaryAttacher attacher(this);
727 glUniform4fv(location, 1, params);
728 }
729
730 lastCanvas = Canvas::current;
731 lastViewport = view;
732 }
733
checkSetPointSize(float size)734 void Shader::checkSetPointSize(float size)
735 {
736 if (size == lastPointSize)
737 return;
738
739 GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
740
741 if (location >= 0)
742 {
743 TemporaryAttacher attacher(this);
744 glUniform1f(location, size);
745 }
746
747 lastPointSize = size;
748 }
749
checkSetBuiltinUniforms()750 void Shader::checkSetBuiltinUniforms()
751 {
752 checkSetScreenParams();
753
754 // We use a more efficient method for sending transformation matrices to
755 // the GPU on desktop GL.
756 if (GLAD_ES_VERSION_2_0)
757 {
758 checkSetPointSize(gl.getPointSize());
759
760 const Matrix4 &curxform = gl.matrices.transform.back();
761 const Matrix4 &curproj = gl.matrices.projection.back();
762
763 TemporaryAttacher attacher(this);
764
765 bool tpmatrixneedsupdate = false;
766
767 // Only upload the matrices if they've changed.
768 if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
769 {
770 GLint location = builtinUniforms[BUILTIN_TRANSFORM_MATRIX];
771 if (location >= 0)
772 glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
773
774 // Also upload the re-calculated normal matrix, if possible. The
775 // normal matrix is the transpose of the inverse of the rotation
776 // portion (top-left 3x3) of the transform matrix.
777 location = builtinUniforms[BUILTIN_NORMAL_MATRIX];
778 if (location >= 0)
779 {
780 Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
781 glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
782 }
783
784 tpmatrixneedsupdate = true;
785 lastTransformMatrix = curxform;
786 }
787
788 if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
789 {
790 GLint location = builtinUniforms[BUILTIN_PROJECTION_MATRIX];
791 if (location >= 0)
792 glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
793
794 tpmatrixneedsupdate = true;
795 lastProjectionMatrix = curproj;
796 }
797
798 if (tpmatrixneedsupdate)
799 {
800 GLint location = builtinUniforms[BUILTIN_TRANSFORM_PROJECTION_MATRIX];
801 if (location >= 0)
802 {
803 Matrix4 tp_matrix(curproj * curxform);
804 glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
805 }
806 }
807 }
808 }
809
getBoundRetainables() const810 const std::map<std::string, Object *> &Shader::getBoundRetainables() const
811 {
812 return boundRetainables;
813 }
814
getGLSLVersion()815 std::string Shader::getGLSLVersion()
816 {
817 const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
818
819 if (tmp == nullptr)
820 return "0.0";
821
822 // the version string always begins with a version number of the format
823 // major_number.minor_number
824 // or
825 // major_number.minor_number.release_number
826 // we can keep release_number, since it does not affect the check below.
827 std::string versionstring(tmp);
828 size_t minorendpos = versionstring.find(' ');
829 return versionstring.substr(0, minorendpos);
830 }
831
isSupported()832 bool Shader::isSupported()
833 {
834 return GLAD_ES_VERSION_2_0 || (getGLSLVersion() >= "1.2");
835 }
836
getUniformTypeSize(GLenum type) const837 int Shader::getUniformTypeSize(GLenum type) const
838 {
839 switch (type)
840 {
841 case GL_INT:
842 case GL_FLOAT:
843 case GL_BOOL:
844 case GL_SAMPLER_1D:
845 case GL_SAMPLER_2D:
846 case GL_SAMPLER_3D:
847 return 1;
848 case GL_INT_VEC2:
849 case GL_FLOAT_VEC2:
850 case GL_FLOAT_MAT2:
851 case GL_BOOL_VEC2:
852 return 2;
853 case GL_INT_VEC3:
854 case GL_FLOAT_VEC3:
855 case GL_FLOAT_MAT3:
856 case GL_BOOL_VEC3:
857 return 3;
858 case GL_INT_VEC4:
859 case GL_FLOAT_VEC4:
860 case GL_FLOAT_MAT4:
861 case GL_BOOL_VEC4:
862 return 4;
863 default:
864 return 1;
865 }
866 }
867
getUniformBaseType(GLenum type) const868 Shader::UniformType Shader::getUniformBaseType(GLenum type) const
869 {
870 switch (type)
871 {
872 case GL_INT:
873 case GL_INT_VEC2:
874 case GL_INT_VEC3:
875 case GL_INT_VEC4:
876 return UNIFORM_INT;
877 case GL_FLOAT:
878 case GL_FLOAT_VEC2:
879 case GL_FLOAT_VEC3:
880 case GL_FLOAT_VEC4:
881 return UNIFORM_FLOAT;
882 case GL_FLOAT_MAT2:
883 case GL_FLOAT_MAT3:
884 case GL_FLOAT_MAT4:
885 case GL_FLOAT_MAT2x3:
886 case GL_FLOAT_MAT2x4:
887 case GL_FLOAT_MAT3x2:
888 case GL_FLOAT_MAT3x4:
889 case GL_FLOAT_MAT4x2:
890 case GL_FLOAT_MAT4x3:
891 return UNIFORM_MATRIX;
892 case GL_BOOL:
893 case GL_BOOL_VEC2:
894 case GL_BOOL_VEC3:
895 case GL_BOOL_VEC4:
896 return UNIFORM_BOOL;
897 case GL_SAMPLER_1D:
898 case GL_SAMPLER_1D_SHADOW:
899 case GL_SAMPLER_1D_ARRAY:
900 case GL_SAMPLER_1D_ARRAY_SHADOW:
901 case GL_SAMPLER_2D:
902 case GL_SAMPLER_2D_MULTISAMPLE:
903 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
904 case GL_SAMPLER_2D_RECT:
905 case GL_SAMPLER_2D_RECT_SHADOW:
906 case GL_SAMPLER_2D_SHADOW:
907 case GL_SAMPLER_2D_ARRAY:
908 case GL_SAMPLER_2D_ARRAY_SHADOW:
909 case GL_SAMPLER_3D:
910 case GL_SAMPLER_CUBE:
911 case GL_SAMPLER_CUBE_SHADOW:
912 case GL_SAMPLER_CUBE_MAP_ARRAY:
913 case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
914 return UNIFORM_SAMPLER;
915 default:
916 return UNIFORM_UNKNOWN;
917 }
918 }
919
getConstant(const char * in,UniformType & out)920 bool Shader::getConstant(const char *in, UniformType &out)
921 {
922 return uniformTypes.find(in, out);
923 }
924
getConstant(UniformType in,const char * & out)925 bool Shader::getConstant(UniformType in, const char *&out)
926 {
927 return uniformTypes.find(in, out);
928 }
929
getConstant(const char * in,VertexAttribID & out)930 bool Shader::getConstant(const char *in, VertexAttribID &out)
931 {
932 return attribNames.find(in, out);
933 }
934
getConstant(VertexAttribID in,const char * & out)935 bool Shader::getConstant(VertexAttribID in, const char *&out)
936 {
937 return attribNames.find(in, out);
938 }
939
940 StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
941 {
942 {"vertex", Shader::STAGE_VERTEX},
943 {"pixel", Shader::STAGE_PIXEL},
944 };
945
946 StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
947
948 StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
949 {
950 {"float", Shader::UNIFORM_FLOAT},
951 {"matrix", Shader::UNIFORM_MATRIX},
952 {"int", Shader::UNIFORM_INT},
953 {"bool", Shader::UNIFORM_BOOL},
954 {"image", Shader::UNIFORM_SAMPLER},
955 {"unknown", Shader::UNIFORM_UNKNOWN},
956 };
957
958 StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
959
960 StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
961 {
962 {"VertexPosition", ATTRIB_POS},
963 {"VertexTexCoord", ATTRIB_TEXCOORD},
964 {"VertexColor", ATTRIB_COLOR},
965 {"ConstantColor", ATTRIB_CONSTANTCOLOR},
966 };
967
968 StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
969
970 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
971 {
972 {"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
973 {"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
974 {"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
975 {"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
976 {"love_PointSize", Shader::BUILTIN_POINT_SIZE},
977 {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
978 {"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
979 {"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
980 {"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
981 };
982
983 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
984
985 } // opengl
986 } // graphics
987 } // love
988