diff --git a/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java b/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java index 6777879fc0d2df4a32a7c63709e19073f0732279..8e6fce0fbea61bf19646be667172f421fae777d1 100644 --- a/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java +++ b/src/main/java/de/hft/stuttgart/citygml/viewer/CityGMLViewer.java @@ -58,6 +58,8 @@ import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GLUtil; +import org.lwjgl.system.Callback; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.lwjgl.util.nfd.NativeFileDialog; @@ -105,6 +107,12 @@ public class CityGMLViewer { } public static void main(String[] args) { + boolean useDebug = false; + for (String arg : args) { + if (arg.equals("-debug")) { + useDebug = true; + } + } File f = null; if (args != null && args.length == 1) { f = new File(args[0]); @@ -117,11 +125,11 @@ public class CityGMLViewer { f = showFileChooserDialog(); } try { - setupWindow(f); + setupWindow(f, useDebug); } catch (Exception e) { - String message = e.getMessage(); + String message = e.getClass().getSimpleName() + ": " + e.getMessage(); if (e.getCause() != null) { - message += "\n" + e.getCause().getMessage(); + message += "\nCause: " + e.getCause().getClass().getSimpleName() + ": " + e.getCause().getMessage(); } JOptionPane.showMessageDialog(null, message, "Error", JOptionPane.ERROR_MESSAGE); } finally { @@ -187,14 +195,19 @@ public class CityGMLViewer { } } - private static void setupWindow(File f) { - GLFW.glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err)); + private static void setupWindow(File f, boolean useDebug) { + GLFW.glfwSetErrorCallback(GLFWErrorCallback.create((code, desc) -> { + log.severe("Encountered OpenGL error with code: " + code); + })); if (!GLFW.glfwInit()) { throw new IllegalStateException("Unable to initialize GLFW"); } String title = "CityGMLViewer"; GLFW.glfwDefaultWindowHints(); // Loads GLFW's default window settings + if (useDebug) { + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); + } GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE); // Sets window to be visible GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE); // Sets whether the window is resizable GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -294,6 +307,11 @@ public class CityGMLViewer { // NO_CURRENT_CONTEXT error org.lwjgl.opengl.GLCapabilities caps = GL.createCapabilities(); // Will let lwjgl know we want to use this // context as the context to draw with + Callback cb = null; + if (useDebug) { + cb = GLUtil.setupDebugMessageCallback(); + } + if (!caps.OpenGL30) { log.warning("OpenGL 3.0 is not supported"); } @@ -314,7 +332,7 @@ public class CityGMLViewer { FloatBuffer clearDepth = null; try { - Shader program = new Shader("vertex.vert", "fragment.frag"); + Shader program = new Shader("vertex.vert", "fragment.frag", useDebug); program.use(); log.fine(() -> "OpenGL error code after shader loading: " + GL11.glGetError()); camera = new Camera(program); @@ -363,6 +381,9 @@ public class CityGMLViewer { } } + if (cb != null) { + cb.free(); + } GLFW.glfwDestroyWindow(windowId); Callbacks.glfwFreeCallbacks(windowId); GLFW.glfwTerminate(); diff --git a/src/main/java/de/hft/stuttgart/citygml/viewer/Shader.java b/src/main/java/de/hft/stuttgart/citygml/viewer/Shader.java index 8432b62becf5850126be8633f881a15a45cba470..1794c7a42595fd6caf53a8c3b5916136e958ebc3 100644 --- a/src/main/java/de/hft/stuttgart/citygml/viewer/Shader.java +++ b/src/main/java/de/hft/stuttgart/citygml/viewer/Shader.java @@ -27,21 +27,29 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UncheckedIOException; +import java.nio.ByteBuffer; import org.lwjgl.opengl.GL20; +import org.lwjgl.system.MemoryUtil; public class Shader { private int programId; - public Shader(String vertexPath, String fragmentPath) { + public Shader(String vertexPath, String fragmentPath, boolean useDebug) { int vertexShader = glCreateShader(GL20.GL_VERTEX_SHADER); glShaderSource(vertexShader, readFully(vertexPath)); glCompileShader(vertexShader); + if (useDebug) { + checkShaderCompilationForErrors(vertexShader); + } + int fragmentShader = glCreateShader(GL20.GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, readFully(fragmentPath)); glCompileShader(fragmentShader); - + if (useDebug) { + checkShaderCompilationForErrors(vertexShader); + } programId = GL20.glCreateProgram(); glAttachShader(programId, vertexShader); glAttachShader(programId, fragmentShader); @@ -51,6 +59,28 @@ public class Shader { glDeleteShader(fragmentShader); } + private void checkShaderCompilationForErrors(int shaderID) { + int[] isCompiled = new int[1]; + GL20.glGetShaderiv(shaderID, GL20.GL_COMPILE_STATUS, isCompiled); + if(isCompiled[0] == 0) { + + int[] maxLength = new int[1]; + GL20.glGetShaderiv(shaderID, GL20.GL_INFO_LOG_LENGTH, maxLength); + // The maxLength includes the NULL character + ByteBuffer stringBuffer = MemoryUtil.memAlloc(maxLength[0]); + GL20.glGetShaderInfoLog(shaderID, maxLength, stringBuffer); + byte[] byteArray = new byte[stringBuffer.capacity()]; + stringBuffer.get(byteArray); + String errorMsg = new String(byteArray); + MemoryUtil.memFree(stringBuffer); + + // Provide the infolog in whatever manor you deem best. + // Exit with failure. + glDeleteShader(shaderID); // Don't leak the shader. + throw new IllegalStateException("Error while compiling shader: " + errorMsg); + } + } + public void use() { glUseProgram(programId); } diff --git a/src/main/resources/fragment.frag b/src/main/resources/fragment.frag index 771dc5959481f64139059787fa484517b3364b67..4999dac6fe2cddbd91238d9116f7259c72e2e94c 100644 --- a/src/main/resources/fragment.frag +++ b/src/main/resources/fragment.frag @@ -1,4 +1,4 @@ -#version 330 +#version 150 core // Incoming interpolated (between vertices) color. @@ -6,7 +6,7 @@ in vec3 interpolatedColor; // Outgoing final color. -layout (location = 0) out vec4 outputColor; +out vec4 outputColor; void main() diff --git a/src/main/resources/vertex.vert b/src/main/resources/vertex.vert index c23f4a8a6ae345aba4b2d605839ecae8472d412c..29eddbe59fa7da0780b5ef60650923b90246e64e 100644 --- a/src/main/resources/vertex.vert +++ b/src/main/resources/vertex.vert @@ -1,11 +1,11 @@ -#version 330 +#version 150 core // Incoming vertex position, Model Space. -layout (location = 0) in vec3 position; +in vec3 position; // Incoming vertex color. -layout (location = 1) in vec3 color; +in vec3 color; // Projection, view and model matrix. uniform mat4 projViewModel;