diff --git a/.gitignore b/.gitignore index 1318d0a..3919f5d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,6 @@ build/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store + +logs \ No newline at end of file diff --git a/pom.xml b/pom.xml index 86e58e0..26b5258 100644 --- a/pom.xml +++ b/pom.xml @@ -6,16 +6,53 @@ me.slinky Tony - 0.0.1 + 0.0.2 - 22 - 22 - UTF-8 - 3.4.1 - natives-windows + 1.10.8 + 1.10.0 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 15 + 15 + + + + + + + + lwjgl-natives-linux-amd64 + + + unix + linux + amd64 + + + + natives-linux + + + + lwjgl-natives-windows-amd64 + + + windows + amd64 + + + + natives-windows + + + @@ -38,170 +75,30 @@ org.lwjgl lwjgl-assimp - - org.lwjgl - lwjgl-bgfx - - - org.lwjgl - lwjgl-egl - - - org.lwjgl - lwjgl-fmod - - - org.lwjgl - lwjgl-freetype - org.lwjgl lwjgl-glfw - - org.lwjgl - lwjgl-harfbuzz - - - org.lwjgl - lwjgl-hwloc - - - org.lwjgl - lwjgl-jawt - - - org.lwjgl - lwjgl-jemalloc - - - org.lwjgl - lwjgl-ktx - - - org.lwjgl - lwjgl-llvm - - - org.lwjgl - lwjgl-lmdb - - - org.lwjgl - lwjgl-lz4 - - - org.lwjgl - lwjgl-meshoptimizer - - - org.lwjgl - lwjgl-msdfgen - - - org.lwjgl - lwjgl-nanovg - - - org.lwjgl - lwjgl-nfd - - - org.lwjgl - lwjgl-nuklear - - - org.lwjgl - lwjgl-odbc - org.lwjgl lwjgl-openal - - org.lwjgl - lwjgl-opencl - org.lwjgl lwjgl-opengl - - org.lwjgl - lwjgl-opengles - - - org.lwjgl - lwjgl-openxr - - - org.lwjgl - lwjgl-opus - - - org.lwjgl - lwjgl-par - - - org.lwjgl - lwjgl-remotery - - - org.lwjgl - lwjgl-renderdoc - - - org.lwjgl - lwjgl-rpmalloc - - - org.lwjgl - lwjgl-sdl - - - org.lwjgl - lwjgl-shaderc - org.lwjgl lwjgl-spng - - org.lwjgl - lwjgl-spvc - org.lwjgl lwjgl-stb - - org.lwjgl - lwjgl-tinyexr - org.lwjgl lwjgl-tinyfd - - org.lwjgl - lwjgl-vma - - - org.lwjgl - lwjgl-vulkan - - - org.lwjgl - lwjgl-xxhash - - - org.lwjgl - lwjgl-yoga - - - org.lwjgl - lwjgl-zstd - org.lwjgl lwjgl @@ -212,81 +109,11 @@ lwjgl-assimp ${lwjgl.natives} - - org.lwjgl - lwjgl-bgfx - ${lwjgl.natives} - - - org.lwjgl - lwjgl-freetype - ${lwjgl.natives} - org.lwjgl lwjgl-glfw ${lwjgl.natives} - - org.lwjgl - lwjgl-harfbuzz - ${lwjgl.natives} - - - org.lwjgl - lwjgl-hwloc - ${lwjgl.natives} - - - org.lwjgl - lwjgl-jemalloc - ${lwjgl.natives} - - - org.lwjgl - lwjgl-ktx - ${lwjgl.natives} - - - org.lwjgl - lwjgl-llvm - ${lwjgl.natives} - - - org.lwjgl - lwjgl-lmdb - ${lwjgl.natives} - - - org.lwjgl - lwjgl-lz4 - ${lwjgl.natives} - - - org.lwjgl - lwjgl-meshoptimizer - ${lwjgl.natives} - - - org.lwjgl - lwjgl-msdfgen - ${lwjgl.natives} - - - org.lwjgl - lwjgl-nanovg - ${lwjgl.natives} - - - org.lwjgl - lwjgl-nfd - ${lwjgl.natives} - - - org.lwjgl - lwjgl-nuklear - ${lwjgl.natives} - org.lwjgl lwjgl-openal @@ -297,95 +124,40 @@ lwjgl-opengl ${lwjgl.natives} - - org.lwjgl - lwjgl-opengles - ${lwjgl.natives} - - - org.lwjgl - lwjgl-openxr - ${lwjgl.natives} - - - org.lwjgl - lwjgl-opus - ${lwjgl.natives} - - - org.lwjgl - lwjgl-par - ${lwjgl.natives} - - - org.lwjgl - lwjgl-remotery - ${lwjgl.natives} - - - org.lwjgl - lwjgl-rpmalloc - ${lwjgl.natives} - - - org.lwjgl - lwjgl-sdl - ${lwjgl.natives} - - - org.lwjgl - lwjgl-shaderc - ${lwjgl.natives} - org.lwjgl lwjgl-spng ${lwjgl.natives} - - org.lwjgl - lwjgl-spvc - ${lwjgl.natives} - org.lwjgl lwjgl-stb ${lwjgl.natives} - - org.lwjgl - lwjgl-tinyexr - ${lwjgl.natives} - org.lwjgl lwjgl-tinyfd ${lwjgl.natives} - - org.lwjgl - lwjgl-vma - ${lwjgl.natives} - - - org.lwjgl - lwjgl-xxhash - ${lwjgl.natives} - - - org.lwjgl - lwjgl-yoga - ${lwjgl.natives} - - - org.lwjgl - lwjgl-zstd - ${lwjgl.natives} - org.joml joml - 1.10.8 + ${joml.version} + + + org.joml + joml-primitives + ${joml-primitives.version} + + + org.apache.logging.log4j + log4j-api + 2.25.3 + + + org.apache.logging.log4j + log4j-core + 2.25.3 diff --git a/src/main/java/DirectionalLight.java b/src/main/java/DirectionalLight.java new file mode 100644 index 0000000..048cb53 --- /dev/null +++ b/src/main/java/DirectionalLight.java @@ -0,0 +1,16 @@ +import org.joml.Vector3f; + +public class DirectionalLight { + public Vector3f direction; + public Vector3f color; + public float intensity; + + public DirectionalLight ( + Vector3f direction, + Vector3f color, + float intensity) { + this.direction = direction; + this.color = color; + this.intensity = intensity; + } +} diff --git a/src/main/java/Mesh.java b/src/main/java/Mesh.java index 8b6dee5..adf7027 100644 --- a/src/main/java/Mesh.java +++ b/src/main/java/Mesh.java @@ -15,35 +15,46 @@ public class Mesh { private int _vbo; private int _ebo; - public void setup(float[] positions, float[] uv, float[] normals, int[] indices) { + private int vertexCount; + + public Mesh(float[] p, float[] u, float[] n, int[] indices) { + vertexCount = indices.length; + sendToGPU(Vertex.interleaveVertexData(p, u, n), indices); + } + + public void render() { + glBindVertexArray(_vao); + glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + } + + public void cleanup() { + glDeleteBuffers(_vbo); + glDeleteBuffers(_ebo); + glDeleteVertexArrays(_vao); + } + + private void sendToGPU(float[] vertices, int[] indices) { try (MemoryStack stack = MemoryStack.stackPush()) { _vao = glGenVertexArrays(); glBindVertexArray(_vao); // pos _vbo = glGenBuffers(); - FloatBuffer posBuffer = stack.mallocFloat(positions.length); - posBuffer.put(positions).flip(); glBindBuffer(GL_ARRAY_BUFFER, _vbo); - glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); + glBufferData(GL_ARRAY_BUFFER, stack.floats(vertices), GL_STATIC_DRAW); - // uv - int uvVbo = glGenBuffers(); - FloatBuffer uvBuffer = stack.mallocFloat(uv.length); - uvBuffer.put(uv).flip(); - glBindBuffer(GL_ARRAY_BUFFER, uvVbo); - glBufferData(GL_ARRAY_BUFFER, uvBuffer, GL_STATIC_DRAW); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0); - - // indices _ebo = glGenBuffers(); - IntBuffer indexBuffer = stack.mallocInt(indices.length); - indexBuffer.put(indices).flip(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, stack.ints(indices), GL_STATIC_DRAW); + + // set vao positions + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, false, STRIDE, 0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, false, STRIDE, 3 * Float.BYTES); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_FLOAT, false, STRIDE, 5 * Float.BYTES); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); diff --git a/src/main/java/OrthoCamera.java b/src/main/java/OrthoCamera.java new file mode 100644 index 0000000..d619edb --- /dev/null +++ b/src/main/java/OrthoCamera.java @@ -0,0 +1,35 @@ +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class OrthoCamera { + private Matrix4f projection; + private Matrix4f view; + + private float size = 10.f; + private Vector3f position = new Vector3f(size, size, size); + + public OrthoCamera(float aspectRatio) { + projection = new Matrix4f().ortho( + -size * aspectRatio, // Left + size * aspectRatio, // Right + -size, // Bottom + size, // Top + 0.01f, // Near + 100.0f // Far + ); + + Vector3f camPos = new Vector3f(10, 10, 10); + Vector3f target = new Vector3f(0, 0, 0); + Vector3f up = new Vector3f(0, 1, 0); + + view = new Matrix4f().lookAt(camPos, target, up); + } + + public Matrix4f getProjection() { + return projection; + } + + public Matrix4f getView() { + return view; + } +} diff --git a/src/main/java/PrimitiveGenerator.java b/src/main/java/PrimitiveGenerator.java index bc40297..9e136af 100644 --- a/src/main/java/PrimitiveGenerator.java +++ b/src/main/java/PrimitiveGenerator.java @@ -3,11 +3,57 @@ import org.joml.Vector3f; public class PrimitiveGenerator { public static Mesh getCube() { - var mesh = new Mesh(); + float s = 0.5f; - Vertex[] vertices = new Vertex[8]; + // Positions: 24 vertices (6 faces * 4 vertices) + float[] p = { + // Front face (z = s) + -s, s, s, -s, -s, s, s, -s, s, s, s, s, + // Back face (z = -s) + -s, s, -s, s, s, -s, s, -s, -s, -s, -s, -s, + // Top face (y = s) + -s, s, -s, -s, s, s, s, s, s, s, s, -s, + // Bottom face (y = -s) + -s, -s, -s, s, -s, -s, s, -s, s, -s, -s, s, + // Right face (x = s) + s, s, s, s, -s, s, s, -s, -s, s, s, -s, + // Left face (x = -s) + -s, s, -s, -s, -s, -s, -s, -s, s, -s, s, s + }; + // UV Coordinates (Standard 0,0 to 1,1 for every face) + float[] u = { + 0,1, 0,0, 1,0, 1,1, // Front + 1,1, 0,1, 0,0, 1,0, // Back + 0,1, 0,0, 1,0, 1,1, // Top + 0,0, 1,0, 1,1, 0,1, // Bottom + 0,1, 0,0, 1,0, 1,1, // Right + 0,1, 0,0, 1,0, 1,1 // Left + }; + + // Normals (Pointing straight out from each face) + float[] n = { + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front + 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Back + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Top + 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Bottom + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Right + -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0 // Left + }; + + // Indices (Two triangles per face) int[] indices = new int[36]; - return mesh; + for (int i = 0; i < 6; i++) { + int offset = i * 4; + int idx = i * 6; + indices[idx + 0] = offset + 0; + indices[idx + 1] = offset + 1; + indices[idx + 2] = offset + 2; + indices[idx + 3] = offset + 2; + indices[idx + 4] = offset + 3; + indices[idx + 5] = offset + 0; + } + + return new Mesh(p, u, n, indices); } } diff --git a/src/main/java/Shader.java b/src/main/java/Shader.java index 0e7096f..84b2c95 100644 --- a/src/main/java/Shader.java +++ b/src/main/java/Shader.java @@ -1,8 +1,23 @@ +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.lwjgl.system.MemoryStack; + +import java.nio.FloatBuffer; +import java.util.HashMap; +import java.util.Vector; + import static org.lwjgl.opengl.GL40.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public class Shader { + private static final Logger logger = LogManager.getLogger(Shader.class); + private final int id; + private final HashMap uniforms = new HashMap<>(); + public Shader(String vertexPath, String fragmentPath) { id = glCreateProgram(); @@ -34,6 +49,56 @@ public class Shader { public void unbind() { glUseProgram(0); } + + public void setUniform(String uniformName, Matrix4f data) { + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer fb = stack.mallocFloat(16); + data.get(fb); + int location = getUniformLocation(uniformName); + if (location < 0) { + var msg = "Failed to find location for uniform name %s".formatted(uniformName); + logger.error(msg); + return; + } + glUniformMatrix4fv(location, false, fb); + } + } + + public void setUniform(String uniformName, Vector3f data) { + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer fb = stack.mallocFloat(3); + data.get(fb); + int location = getUniformLocation(uniformName); + if (location < 0) { + var msg = "Failed to find location for uniform name %s".formatted(uniformName); + logger.error(msg); + return; + } + glUniform3fv(location, fb.array()); + } + } + + public void setUniform(String uniformName, float data) { + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer fb = stack.mallocFloat(1); + fb.put(data); + int location = getUniformLocation(uniformName); + if (location < 0) { + var msg = "Failed to find location for uniform name %s".formatted(uniformName); + logger.error(msg); + return; + } + glUniform1f(location, fb.get(0)); + } + } + + private int getUniformLocation(String uniformName) { + if (!uniforms.containsKey(uniformName)) { + int location = glGetUniformLocation(id, uniformName); + uniforms.put(uniformName, location); + } + return uniforms.get(uniformName); + } } diff --git a/src/main/java/Tony.java b/src/main/java/Tony.java index fde520b..66c1ac6 100644 --- a/src/main/java/Tony.java +++ b/src/main/java/Tony.java @@ -1,11 +1,11 @@ +import org.joml.Matrix4f; +import org.joml.Vector3f; import org.lwjgl.*; import org.lwjgl.glfw.*; import org.lwjgl.opengl.*; import org.lwjgl.system.*; import java.nio.*; -import java.util.logging.Level; -import java.util.logging.Logger; import static org.lwjgl.glfw.Callbacks.*; import static org.lwjgl.glfw.GLFW.*; @@ -13,20 +13,35 @@ import static org.lwjgl.opengl.GL40.*; import static org.lwjgl.system.MemoryStack.*; import static org.lwjgl.system.MemoryUtil.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public class Tony { private long window; private Shader shader; + private Mesh cube; + private OrthoCamera camera; + private DirectionalLight sun; - private static final Logger LOGGER = Logger.getLogger( Tony.class.getName() ); + private static final Logger logger = LogManager.getLogger(Tony.class); public void run() { - LOGGER.log(Level.INFO, "Tony version: %s".formatted(Version.getVersionString())); - LOGGER.log(Level.INFO, "LWJGL version: %s".formatted(org.lwjgl.Version.getVersion())); + logger.info("Tony version: %s".formatted(Version.getVersionString())); + logger.info("LWJGL version: %s".formatted(org.lwjgl.Version.getVersion())); init(); // setup game objects shader = new Shader("/shaders/basic.vert", "/shaders/basic.frag"); + cube = PrimitiveGenerator.getCube(); + + camera = new OrthoCamera(1024.f / 720); + + sun = new DirectionalLight( + new Vector3f(-1.0f, -1.0f, -0.5f), // Pointing Down, Left, and slightly Back + new Vector3f(1.0f, 1.0f, 0.9f), // Warm yellowish sun + 1.2f // Brightness + ); loop(); @@ -75,19 +90,37 @@ public class Tony { } // the stack frame is popped automatically glfwMakeContextCurrent(window); + GL.createCapabilities(); + + glViewport(0, 0, 1024, 720); glfwSwapInterval(1); glfwShowWindow(window); } private void loop() { - GL.createCapabilities(); + glClearColor(0.33f, 0.48f, 0.48f, 1.0f); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + Matrix4f modelMatrix = new Matrix4f(); while ( !glfwWindowShouldClose(window) ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + shader.bind(); + + modelMatrix.rotateXYZ(0, 0.01f, 0); + + shader.setUniform("projection", camera.getProjection()); + shader.setUniform("view", camera.getView()); + shader.setUniform("model", modelMatrix); + shader.setUniform("lightDirection", sun.direction); + shader.setUniform("lightColor", sun.color); + shader.setUniform("lightIntensity", sun.intensity); + + cube.render(); + + shader.unbind(); + glfwSwapBuffers(window); glfwPollEvents(); diff --git a/src/main/java/Version.java b/src/main/java/Version.java index 914270d..847e8bb 100644 --- a/src/main/java/Version.java +++ b/src/main/java/Version.java @@ -10,5 +10,5 @@ public class Version { public static final int VERSION_MAJ = 0; public static final int VERSION_MIN = 0; - public static final int VERSION_PATCH = 1; + public static final int VERSION_PATCH = 2; } \ No newline at end of file diff --git a/src/main/java/Vertex.java b/src/main/java/Vertex.java index 09b901c..352b82c 100644 --- a/src/main/java/Vertex.java +++ b/src/main/java/Vertex.java @@ -5,4 +5,26 @@ public class Vertex { public Vector3f position; public Vector2f uv; public Vector3f norm; + + public static float[] interleaveVertexData(float[] positions, float[] uvs, float[] norms) { + int vertexCount = positions.length / 3; + float[] result = new float[vertexCount * 8]; + + for (int i = 0; i < vertexCount; i++) { + result[i * 8] = positions[i * 3]; + result[i * 8 + 1] = positions[i * 3 + 1]; + result[i * 8 + 2] = positions[i * 3 + 2]; + + // UVs (2 floats) + result[i * 8 + 3] = uvs[i * 2]; + result[i * 8 + 4] = uvs[i * 2 + 1]; + + // Normals (3 floats) + result[i * 8 + 5] = norms[i * 3]; + result[i * 8 + 6] = norms[i * 3 + 1]; + result[i * 8 + 7] = norms[i * 3 + 2]; + } + + return result; + } } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..cf7d604 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/shaders/basic.frag b/src/main/resources/shaders/basic.frag index 2371ee4..01068c2 100644 --- a/src/main/resources/shaders/basic.frag +++ b/src/main/resources/shaders/basic.frag @@ -2,6 +2,24 @@ out vec4 color; +in vec2 texCoord; +in vec3 normal; + +uniform sampler2D texture_diffuse; +uniform vec3 lightDirection; +uniform vec3 lightColor; +uniform float lightIntensity; + void main() { - color = vec4(1.0, 0.0, 0.0, 1.0); + vec3 normal = normalize(outNormal); + vec3 lightDir = normalize(-lightDirection); + + float diff = max(dot(normal, lightDir), 0.0); + + float ambient = 0.2; + + vec3 diffuse = diff * lightColor * lightIntensity; + vec4 texColor = texture(texture_diffuse, texCoord); + + color = vec4(ambient + diffuse, 1.0) * texColor; } \ No newline at end of file diff --git a/src/main/resources/shaders/basic.vert b/src/main/resources/shaders/basic.vert index 0c0f21a..23410ca 100644 --- a/src/main/resources/shaders/basic.vert +++ b/src/main/resources/shaders/basic.vert @@ -1,6 +1,8 @@ #version 400 core layout (location = 0) in vec3 position; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec3 uniform mat4 model; uniform mat4 view;