Orthographic projection matrix?

Hello JGO, this one’s pretty simple:

I have the basics of a 2d batch drawer. Currently there are no projection, view, or model matrices involved, which I’m attempting to fix today.

I changed the shader from this:

#version 330

layout (location=0) in vec2 inPosition;
layout (location=1) in vec2 inTexCoord;

out vec2 vTexCoord;

void main() {
	gl_Position = vec4(inPosition, 0.0, 1.0);
	vTexCoord = inTexCoord;
}

To this:

#version 330

layout (location=0) in vec2 inPosition;
layout (location=1) in vec2 inTexCoord;

out vec2 vTexCoord;

uniform mat4 projectionMatrix;

void main() {
	gl_Position = projectionMatrix * vec4(inPosition, 0.0, 1.0);
	vTexCoord = inTexCoord;
}

And I then supplied the shader with a bog-standard JOML matrix4f:

Matrix4f proj = new Matrix4f();
proj.identity().setOrtho(0, window.getWidth(), 0, window.getHeight(), -1f, 1f);
shader.setUniform("projectionMatrix", proj);
glViewport(0, 0, window.getWidth(), window.getHeight());

Now, no matter what corners or sizes of quads I supply, I don’t get anything rendered on the screen.

Am I missing something obvious here?

EDIT:

In the interest of providing a bit more insight, here is the code for the batcher:

package com.eli.game.render;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.lwjgl.system.MemoryUtil;

public class Batcher {

	private int vaoID;

	private int indID, posID, texID;
	private FloatBuffer posBuf;
	private FloatBuffer texBuf;

	private ShaderProgram shader;
	
	Matrix4f ortho;

	private boolean drawing;
	private int drawCount;

	public void init(int quadsPerBatch, Window window) {

		// create VAO
		vaoID = glGenVertexArrays();
		glBindVertexArray(vaoID);

		// Create index buffer, and initialize values; draw order won't be changing.
		int[] indices = new int[quadsPerBatch * 6]; // # quads * 6 indices per quad, 3 per triangle
		int j = 0;
		for (int i = 0; i < indices.length; i+=6, j+=4) {
			indices[i + 0] = j + 0;
			indices[i + 1] = j + 1;
			indices[i + 2] = j + 2;
			indices[i + 3] = j + 3;
			indices[i + 4] = j + 0;
			indices[i + 5] = j + 2;
		}
		indID = glGenBuffers();
		IntBuffer ib = MemoryUtil.memAllocInt(indices.length);
		ib.put(indices).flip();
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indID);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, ib, GL_DYNAMIC_DRAW);
		MemoryUtil.memFree(ib);

		// create position buffer
		posID = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, posID);
		posBuf = MemoryUtil.memAllocFloat(quadsPerBatch * 4 * 2); // # quads * 4 verts per quad * 2 attribs per vert
		long size = posBuf.capacity() * Float.BYTES;
		glBufferData(GL_ARRAY_BUFFER, size, GL_DYNAMIC_DRAW);
		glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

		// Create texture buffer
		texID = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, texID);
		texBuf = MemoryUtil.memAllocFloat(quadsPerBatch * 4 * 2); // # quads * 4 verts per quad * 2 attribs per vert
		size = texBuf.capacity() * Float.BYTES;
		glBufferData(GL_ARRAY_BUFFER, size, GL_DYNAMIC_DRAW);
		glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);

		glBindBuffer(GL_ARRAY_BUFFER, 0);
		
		// Initialize variables
		drawCount = 0;
		drawing = false;

		// Load shader
		shader = new ShaderProgram();
		shader.loadVertexShader("./resources/shaders/basic/basic.vs");
		shader.loadFragmentShader("./resources/shaders/basic/basic.fs");
		shader.link();

		// Create and set shader uniforms
		shader.createUniform("texture_sampler");
		shader.createUniform("projectionMatrix");
		shader.setUniform("texture_sampler", 0);
		
		ortho = new Matrix4f();
		ortho.identity().setOrtho(0, window.getWidth(), 0, window.getHeight(), -1f, 1f);
		shader.setUniform("projectionMatrix", ortho);
		glViewport(0, 0, window.getWidth(), window.getHeight());

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	}

	public void clear() {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}

	public void begin() {
		if (drawing) {
			throw new IllegalStateException("Already drawing.");
		}
		drawing = true;
		drawCount = 0;
	}

	public void end() {
		if (!drawing) {
			throw new IllegalStateException("Not drawing.");
		}
		drawing = false;
		flush();
	}

	/** Flush data to GPU and render. */
	public void flush() {

		// Only flush if there's information *to* flush.
		if (drawCount > 0) {

			// Bind VAO
			glBindVertexArray(vaoID);
			
			// Flip position buffer, and send to GPU
			posBuf.flip();
			glBindBuffer(GL_ARRAY_BUFFER, posID);
			glBufferSubData(GL_ARRAY_BUFFER, 0, posBuf);
			glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

			// Flip texture buffer, and send to GPU
			texBuf.flip();
			glBindBuffer(GL_ARRAY_BUFFER, texID);
			glBufferSubData(GL_ARRAY_BUFFER, 0, texBuf);
			glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);

			// Bind shader
			shader.bind();
			
			// Set texture
			shader.setUniform("texture_sampler", 0);
			
			// Enable necessary vertex attributes, draw the data, and restore state.
			glEnableVertexAttribArray(0);
			glEnableVertexAttribArray(1);

			glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_INT, 0);

			glDisableVertexAttribArray(0);
			glDisableVertexAttribArray(1);

			// Unbind VAO
			glBindVertexArray(0);
			
			// Clear vertices for next batch
			posBuf.clear();
			texBuf.clear();
			drawCount = 0;
		}
	}
	
	public void drawPolarRect(TextureRegion tex, float elevation, float height, float startAngle, float endAngle) {

		if (posBuf.remaining() < 2 * 4 * 2) { // 2 vertex attribs, 4 vertices, 2 components per vert
			System.out.println("Not enough data remaining in VBO, flushing.");
			flush();
		}

		float angle1 = (float) Math.toRadians(startAngle); // lesser angle
		float angle2 = (float) Math.toRadians(endAngle); // greater angle

		// Draw order:

		//  0     1--0
		//  |\     \ |
		//  | \     \|
		//  1--2     2

		// top left (greater angle, larger radius)
		posBuf.put((float) Math.cos(angle2) * (elevation + height));
		posBuf.put((float) Math.sin(angle2) * (elevation + height));

		// bottom left (greater angle, smaller radius)
		posBuf.put((float) Math.cos(angle2) * elevation);
		posBuf.put((float) Math.sin(angle2) * elevation);

		// bottom right (smaller angle, smaller radius)
		posBuf.put((float) Math.cos(angle1) * elevation);
		posBuf.put((float) Math.sin(angle1) * elevation);

		// top right (smaller angle, greater radius
		posBuf.put((float) Math.cos(angle1) * (elevation + height));
		posBuf.put((float) Math.sin(angle1) * (elevation + height));

		// Textures
		texBuf.put(tex.getU1()).put(tex.getV2());
		texBuf.put(tex.getU1()).put(tex.getV1());
		texBuf.put(tex.getU2()).put(tex.getV1());
		texBuf.put(tex.getU2()).put(tex.getV2());

		drawCount += 6;
	}

	public void drawQuad(Vector2f topLeft, Vector2f bottomLeft, Vector2f bottomRight, Vector2f topRight, float u1, float u2, float v1, float v2) {

		posBuf.put(topLeft.x).put(topLeft.y);
		posBuf.put(bottomLeft.x).put(bottomLeft.y);
		posBuf.put(bottomRight.x).put(bottomRight.y);
		posBuf.put(topRight.x).put(topRight.y);

		texBuf.put(u1).put(v2);
		texBuf.put(u1).put(v1);
		texBuf.put(u2).put(v1);
		texBuf.put(u2).put(v2);

		drawCount += 6;
	}
	
	public void drawQuad(float x, float y, float width, float height, float u1, float u2, float v1, float v2) {
		posBuf.put(x)			.put(y + height);
		posBuf.put(x)			.put(y);
		posBuf.put(x + width)	.put(y);
		posBuf.put(x + width)	.put(y + height);
		
		texBuf.put(u1).put(v2);
		texBuf.put(u1).put(v1);
		texBuf.put(u2).put(v1);
		texBuf.put(u2).put(v2);
		
		drawCount += 6;
	}
}