Sorry for the late reaction, college kinda screwed me over with quite the workload. I hope you, or someone else is interested in looking into my renderer class and shaders. I’ve looked through it myself and can’t find anything out of place.
If someone knows a good book/link that details this kind of stuff, I’d love that too.
Renderer, evolved from the lwjgl opengl tutorials
package varelse;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.*;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;
public class Renderer {
public final static String WINDOW_TITLE = "Varelse";
private final int WIDTH = 1500;
private final int HEIGHT = 800;
private final double PI = 3.14159265358979323846;
public int projectionMatrixLocation = 0; // OpenGL gives an integer to find objects at, this stores that
public int viewMatrixLocation = 0;
public int modelMatrixLocation = 0;
private Matrix4f projectionMatrix = null;
public Matrix4f viewMatrix = null;
public Matrix4f modelMatrix = null;
public Camera cameraModelling;
public QuaternionCamera qCam;
public Vector3f cameraPos = null;
public Vector3f cameraAngle = null;
private FloatBuffer matrix4fBuffer = null;
private int vsId = 0;
private int fsId = 0;
public int pId = 0;
public static ArrayList<Drawable> drawList;
public Renderer() {
drawList = new ArrayList<Drawable>();
cameraModelling = new CameraModelling();
qCam = new QuaternionCamera();
Utils.renderer = this;
setupOpenGL();
setupMatrices();
setupShaders();
setupRenderables();
}
private void setupRenderables() {
drawList.add(new RenderCube(modelMatrixLocation, matrix4fBuffer, vsId, fsId, pId));
drawList.add(new RenderSelectBox(modelMatrixLocation, matrix4fBuffer, pId));
}
private void setupShaders() {
int errorCheckValue = GL11.glGetError();
// Load the vertex shader
vsId = Renderer.loadShader("res/shaders/Vertex.glsl", GL20.GL_VERTEX_SHADER);
// Load the fragment shader
fsId = Renderer.loadShader("res/shaders/Fragment.glsl", GL20.GL_FRAGMENT_SHADER);
// Create a new shader program that links both shaders
pId = GL20.glCreateProgram();
GL20.glAttachShader(pId, vsId);
GL20.glAttachShader(pId, fsId);
GL20.glLinkProgram(pId);
// Position information will be attribute 0
GL20.glBindAttribLocation(pId, 0, "in_Position");
// Color information will be attribute 1
GL20.glBindAttribLocation(pId, 1, "in_Color");
// Texture information will be attribute 2
GL20.glBindAttribLocation(pId, 2, "in_TextureCoord");
GL20.glValidateProgram(pId);
// Get the matrices uniform locations
projectionMatrixLocation = GL20.glGetUniformLocation(pId, "projectionMatrix");
viewMatrixLocation = GL20.glGetUniformLocation(pId, "viewMatrix");
modelMatrixLocation = GL20.glGetUniformLocation(pId, "modelMatrix");
errorCheckValue = GL11.glGetError();
if (errorCheckValue != GL11.GL_NO_ERROR) {
System.out.println("ERROR - Could not create the shaders:" + GLU.gluErrorString(errorCheckValue));
System.exit(-1);
}
}
private void setupMatrices() {
// Setup projection Matrix
projectionMatrix = new Matrix4f();
float fieldOfView = 60f;
float aspectRatio = (float)WIDTH / (float) HEIGHT;
float near_plane = 0.01f;
float far_plane = 100f;
float y_scale = this.coTangent(this.degreesToRadians(fieldOfView / 2f));
float x_scale = y_scale / aspectRatio;
float frustum_length = far_plane - near_plane;
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((far_plane + near_plane) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * near_plane * far_plane) / frustum_length);
viewMatrix = qCam.getCameraMatrix();
// Create a FloatBuffer with the proper size to store our matrices later
matrix4fBuffer = BufferUtils.createFloatBuffer(16);
Main.exitOnGLError("Error in setupMatrices");
}
public void setupOpenGL() {
// Setup an OpenGL context with API version 3.2
try {
PixelFormat pixelFormat = new PixelFormat();
ContextAttribs contextAtrributes = new ContextAttribs(3, 2)
.withForwardCompatible(true)
.withProfileCore(true);
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.setTitle(WINDOW_TITLE);
Display.create(pixelFormat, contextAtrributes);
GL11.glViewport(0, 0, WIDTH, HEIGHT);
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(-1);
}
// Enable face culling
GL11.glEnable(GL11.GL_CULL_FACE);
// Enable depth testing (for gluUnProject
GL11.glEnable(GL11.GL_DEPTH_TEST);
// Setup an XNA like background color
GL11.glClearColor(0.4f, 0.6f, 0.9f, 0f);
//GL11.glClearColor(1.0f, 1.0f, 1.0f, 0f);
// Map the internal OpenGL coordinate system to the entire screen
GL11.glViewport(0, 0, WIDTH, HEIGHT);
Main.exitOnGLError("Error in setupOpenGL");
}
public void matrixLogic() {
viewMatrix = qCam.getCameraMatrix();
GL20.glUseProgram(pId);
// Upload matrices to the uniform variables
projectionMatrix.store(matrix4fBuffer);
matrix4fBuffer.flip();
GL20.glUniformMatrix4(projectionMatrixLocation, false, matrix4fBuffer);
viewMatrix.store(matrix4fBuffer);
matrix4fBuffer.flip();
GL20.glUniformMatrix4(viewMatrixLocation, false, matrix4fBuffer);
GL20.glUseProgram(0);
Main.exitOnGLError("Error in matrixLogic");
}
public void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
for (Drawable d : drawList) {
d.renderSubs();
}
}
public long addRenderable(Drawable d) {
drawList.add(d);
long index = drawList.indexOf(d);
return index;
}
public void removeRenderable(long i) {
drawList.remove(i);
}
public static int loadPNGTexture(String filename, int textureUnit) {
ByteBuffer buf = null;
int tWidth = 0;
int tHeight = 0;
try {
// Open the PNG file as an InputStream
InputStream in = new FileInputStream(filename);
// Link the PNG decoder to this stream
PNGDecoder decoder = new PNGDecoder(in);
// Get the width and height of the texture
tWidth = decoder.getWidth();
tHeight = decoder.getHeight();
// Decode the PNG file in a ByteBuffer
buf = ByteBuffer.allocateDirect(
4 * decoder.getWidth() * decoder.getHeight());
decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
buf.flip();
in.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
// Create a new texture object in memory and bind it
int texId = GL11.glGenTextures();
GL13.glActiveTexture(textureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
// All RGB bytes are aligned to each other and each component is 1 byte
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
// Upload the texture data and generate mip maps (for scaling)
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0,
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
// Setup the ST coordinate system
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
// Setup what to do when the texture has to be scaled
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
GL11.GL_LINEAR_MIPMAP_LINEAR);
Main.exitOnGLError("loadPNGTexture");
return texId;
}
public static int loadShader(String filename, int type) {
StringBuilder shaderSource = new StringBuilder();
int shaderID = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
while ((line = reader.readLine()) != null) {
shaderSource.append(line).append("\n");
}
reader.close();
} catch (IOException e) {
System.err.println("Could not read file.");
e.printStackTrace();
System.exit(-1);
}
shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
// GL20.glGetShader was deprecated, was told to use GL20.glGetShaderi. Still takes the same params though...
if (GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
System.err.println("Could not compile shader.");
System.exit(-1);
}
return shaderID;
}
private float coTangent(float angle) {
return (float)(1f / Math.tan(angle));
}
private float degreesToRadians(float degrees) {
return degrees * (float)(PI / 180d);
}
public void destroy() {
// TODO call destroy on RenderObjects and destroy ?matrices? and openGL
for (Drawable d: drawList){
d.destroy();
}
// Delete the shaders
GL20.glUseProgram(0);
GL20.glDetachShader(pId, vsId);
GL20.glDetachShader(pId, fsId);
GL20.glDeleteShader(vsId);
GL20.glDeleteShader(fsId);
GL20.glDeleteProgram(pId);
}
public void exitOnGLError(String errorMessage) {
int errorValue = GL11.glGetError();
if (errorValue != GL11.GL_NO_ERROR) {
String errorString = GLU.gluErrorString(errorValue);
System.err.println("FUCK, SORRY MAN! Didn't mean to do this D: Here's an error to give to the dev - " + errorMessage + ": " + errorString);
if (Display.isCreated()) Display.destroy();
System.exit(-1);
}
}
public Matrix4f getModelMatrix() {
return modelMatrix;
}
public void setModelMatrix(Matrix4f modelMatrix) {
this.modelMatrix = modelMatrix;
}
}
Vertex shader
# version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;
out vec4 pass_Color;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = in_Position;
// Override gl_Position with our new calculated position
gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position;
pass_Color = in_Color;
pass_TextureCoord = in_TextureCoord;
}
Fragment shader
#version 150 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_TextureCoord;
out vec4 out_Color;
void main(void) {
out_Color = pass_Color;
// Override out_Color with the texture pixel (AAAAH, so that's why!)
out_Color = texture2D(texture_diffuse, pass_TextureCoord);
}