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;