Ver Fonte

Adding error printers for shader.

Sam Jaffe há 6 anos atrás
pai
commit
4362be3733
1 ficheiros alterados com 99 adições e 8 exclusões
  1. 99 8
      graphics/src/opengl_helper.cxx

+ 99 - 8
graphics/src/opengl_helper.cxx

@@ -8,7 +8,9 @@
 
 #include "helper.hpp"
 
+#include <iostream>
 #include <memory>
+#include <sstream>
 #ifdef __APPLE__
 #include <OpenGL/gl3.h>
 #endif
@@ -19,6 +21,89 @@
 #include "game/util/env.hpp"
 #include "game/util/files.hpp"
 
+namespace {
+  typedef void (*GLGetIntFor)(GLuint, GLenum, GLint *);
+  typedef void (*GLGetLog)(GLuint, GLsizei, GLsizei *, GLchar *);
+  struct opengl_error_formatter {
+    void operator()() const;
+    static void shader_error(GLuint id, std::string const & path);
+
+    GLuint obj;
+    std::string fileName, path, eNoticeMessage, eFileMessage, eWindowTitle;
+    GLGetIntFor getIntv;
+    GLGetLog getInfoLog;
+  };
+
+  void opengl_error_formatter::operator()() const {
+    std::stringstream errorString;
+    std::string errorLineNumber;
+
+    int infologLength = 0;
+    int maxLength = 0;
+
+    getIntv(obj, GL_INFO_LOG_LENGTH, &maxLength);
+    errorString << eNoticeMessage << "\n";
+
+    std::unique_ptr<char[]> infoLog(new char[maxLength + 1]);
+    getInfoLog(obj, maxLength, &infologLength, infoLog.get());
+
+    std::string errorLog(infoLog.get());
+    infoLog.reset();
+    if (infologLength <= 0) return;
+
+    std::size_t openParen = errorLog.find('(');
+    std::size_t closeParen = errorLog.find(')');
+    errorLineNumber =
+        errorLog.substr(openParen + 1, closeParen - openParen - 1);
+
+    errorString << fileName << " , "
+                << "line " << errorLineNumber << ":\n";
+
+    std::string errorStart = errorLog.find("error") != std::string::npos
+                                 ? errorLog.substr(errorLog.find("error"))
+                                 : errorLog;
+
+    errorString << errorLog << "\n";
+
+    errorString << "OpenGL Version: " << glGetString(GL_VERSION) << "\n";
+    errorString << "GLSL Shading Version: "
+                << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n";
+
+    errorString << eFileMessage << "\n";
+    errorString << "RAW ERROR LOG: " << errorLog;
+
+    std::stringstream consoleOutput;
+
+    consoleOutput << "1>" << path << '(' << errorLineNumber << ')' << ": "
+                  << errorStart
+                  << "in OpenGL version: " << glGetString(GL_VERSION) << " and "
+                  << "GLSL Shading Version: "
+                  << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
+
+#ifdef _WIN32
+    OutputDebugStringA(consoleOutput.str().c_str());
+    MessageBoxA(nullptr, errorString.str().c_str(), eWindowTitle.c_str(),
+                MB_OK);
+#else
+    std::cerr << consoleOutput.str() << std::endl;
+    std::cerr << errorString.str() << std::endl;
+#endif
+  }
+
+  void opengl_error_formatter::shader_error(GLuint id,
+                                            std::string const & path) {
+    std::string fileName = path.substr(path.find_last_of("/"));
+    opengl_error_formatter{id,
+                           fileName,
+                           path,
+                           "GLSL shader compile error!",
+                           "File location" + path,
+                           "GLSL Compile Error in " + fileName,
+                           glGetShaderiv,
+                           glGetShaderInfoLog}();
+  }
+}
+
 namespace graphics { namespace textures {
   static int glfmt(format color_fmt) {
     switch (color_fmt) {
@@ -97,17 +182,22 @@ namespace graphics { namespace textures {
 }}
 
 namespace graphics { namespace shaders {
+  struct file_read_error : std::runtime_error {
+    using std::runtime_error::runtime_error;
+  };
+
+  struct compilation_error : std::runtime_error {
+    using std::runtime_error::runtime_error;
+  };
+
   unsigned int init(unsigned int type, std::string const & path) {
     unsigned int id;
-    int return_code;
-
     std::unique_ptr<char const[]> buffer;
 
     // 1. Load the vertex shader code (text file) to a new memory buffer
-    if ((buffer = files::load(env::resource_file(path)))) {
-      //      dbgprintf("Shader file %s could not be opened successfully.\n",
-      //      path.c_str());
-      assert(false);
+    std::string const abs_path = env::resource_file(path);
+    if ((buffer = files::load(abs_path))) {
+      throw file_read_error("Could not load shader file " + abs_path);
     }
 
     // 2. Create a new shader ID
@@ -122,11 +212,12 @@ namespace graphics { namespace shaders {
     glCompileShader(id);
 
     // 5. Check for compile errors
+    int return_code;
     glGetShaderiv(id, GL_COMPILE_STATUS, &return_code);
 
     if (return_code != GL_TRUE) {
-      //      LogShaderError(id, path);
-      //      throw shader_instantiation_exception();
+      opengl_error_formatter::shader_error(id, abs_path);
+      throw compilation_error("Could not compile the shader file");
     }
     return id;
   }