You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ShaderLoader.cpp 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include "ShaderLoader.h"
  2. #include <stdlib.h>
  3. #include <fstream>
  4. #include <iostream>
  5. #include "Shader.h"
  6. #include "../../Log.h"
  7. #include "../../environment/Environment.h"
  8. #include "../../environment/Path.h"
  9. static constexpr GLint maxLogSize = 1024 * 1024 * 2; //2 MiB
  10. ShaderLoader::ShaderCache ShaderLoader::shaderCache;
  11. GLuint ShaderLoader::loadShader(const std::string &shaderName, Shader::Type type) {
  12. GLenum glType = getGlShaderType(type);
  13. if (!glType) {
  14. logError() << "Unknown shader type: " << type << std::endl;
  15. return 0;
  16. }
  17. GLuint shader = glCreateShader(glType);
  18. std::string path = Path::fromUnixPath(Environment::getResourceDir() + "/shaders/" + shaderName);
  19. std::ifstream file(path, std::ifstream::ate);
  20. if (!file.is_open()) {
  21. logError() << "Could not open shader " << shaderName << std::endl;
  22. return 0;
  23. }
  24. int fileSize = file.tellg();
  25. file.seekg(std::ifstream::beg);
  26. char *buffer = (char*) malloc(fileSize + 1);
  27. file.read(buffer, fileSize);
  28. buffer[fileSize] = 0;
  29. glShaderSource(shader, 1, &buffer, NULL);
  30. glCompileShader(shader);
  31. free(buffer);
  32. if(checkShader(shader, shaderName, type))
  33. return 0;
  34. return shader;
  35. }
  36. GLuint ShaderLoader::createProgram(const std::string &shader1Name, Shader::Type shader1Type,
  37. const std::string &shader2Name, Shader::Type shader2Type) {
  38. GLuint shader1 = loadShader(shader1Name, shader1Type);
  39. GLuint shader2 = loadShader(shader2Name, shader2Type);
  40. if (!shader1 || !shader2)
  41. return 0;
  42. GLuint program = glCreateProgram();
  43. glAttachShader(program, shader1);
  44. glAttachShader(program, shader2);
  45. glLinkProgram(program);
  46. if (checkProgram(program, GL_LINK_STATUS, shader1Name))
  47. return 0;
  48. /* glValidateProgram(program);
  49. if (checkProgram(program, GL_VALIDATE_STATUS, shader1Name))
  50. return 0; */
  51. return program;
  52. }
  53. Shader *ShaderLoader::getShader(VertexShader vertexShader, FragmentShader fragmentShader) {
  54. // concatenate strings to create unique key for the shader
  55. std::string key = vertexShader.name + fragmentShader.name;
  56. // has the shader been cached?
  57. auto it = shaderCache.find(key);
  58. if (it != shaderCache.end())
  59. return it->second;
  60. // Ok. It isn't. Let's create the shader Q.Q
  61. GLuint program = createProgram(vertexShader.name, Shader::Type::Vertex,
  62. fragmentShader.name, Shader::Type::Fragment);
  63. if (!program) //reee it failed
  64. return NULL;
  65. Shader *shader = new Shader(program);
  66. shaderCache.insert(std::make_pair(key, shader));
  67. return shader;
  68. }
  69. int ShaderLoader::checkShader(GLuint shader, const std::string &shaderName, Shader::Type type) {
  70. GLint success = 0;
  71. glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
  72. if (success == GL_TRUE) {
  73. logDebug() << "Shader " << shaderName << " compiled successfully!" << std::endl;
  74. } else {
  75. GLint logSize = 0;
  76. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
  77. if (logSize > maxLogSize) {
  78. logError() << "Shader " << shaderName << " failed to compile but \
  79. the log is too long to show." << std::endl;
  80. return 1;
  81. }
  82. char log[logSize];
  83. glGetShaderInfoLog(shader, logSize, &logSize, &log[0]);
  84. logError() << "Shader " << shaderName << " failed to compile. GL log output: "
  85. << log << std::endl;
  86. glDeleteShader(shader);
  87. return 1;
  88. }
  89. return 0;
  90. }
  91. int ShaderLoader::checkProgram(GLuint program, GLenum pname, const std::string &shaderName) {
  92. GLint success = 0;
  93. glGetProgramiv(program, pname, &success);
  94. if (success == GL_TRUE) {
  95. logDebug() << "Program with shader1 " << shaderName << " " << getProgramStatusString(pname)
  96. << std::endl;
  97. } else {
  98. GLint logSize = 0;
  99. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logSize);
  100. if (logSize > maxLogSize) {
  101. logError() << "Program with shader1 " << shaderName << " failed to be "
  102. << getProgramStatusString(pname) << " but the log is too long to show" << std::endl;
  103. return 1;
  104. }
  105. char log[logSize];
  106. glGetProgramInfoLog(program, logSize, &logSize, &log[0]);
  107. logError() << "Program with shader1 " << shaderName << " failed to be "
  108. << getProgramStatusString(pname) << ". GL log output: " << log << std::endl;
  109. glDeleteProgram(program);
  110. return 1;
  111. }
  112. return 0;
  113. }
  114. constexpr const char *ShaderLoader::getProgramStatusString(GLenum pname) {
  115. switch (pname) {
  116. case GL_LINK_STATUS:
  117. return "linked";
  118. case GL_VALIDATE_STATUS:
  119. return "validated";
  120. }
  121. return "";
  122. }
  123. constexpr GLenum ShaderLoader::getGlShaderType(const Shader::Type type) {
  124. switch (type) {
  125. case Shader::Vertex:
  126. return GL_VERTEX_SHADER;
  127. case Shader::Fragment:
  128. return GL_FRAGMENT_SHADER;
  129. }
  130. return 0;
  131. }