massive refactor

This commit is contained in:
JISAUAY committed 2024-09-24 17:00:18 -05:00
1 parent 26c0f433ae
commit e71a1a9b0b
14 files changed
+442 -275

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
package org.xfe.engine;
import org.joml.*;
import java.lang.Math;
public class Engine
{
public static final int TARGET_UPS = 30;
private final GameLogic gameLogic;
private final Render render;
private final Window window;
private final World world;
private int target_fps;
private int target_ups;
private boolean running;
public static final float Z_FAR = 1000.0f;
public static final float Z_NEAR = 0.1f;
public static final float FOV = (float) Math.toRadians(90.0f);
public Engine(String window_title, Window.WindowOptions opts, GameLogic gameLogic) {
window = new Window(window_title, opts, () -> {
resize();
return null;
});
target_fps = opts.fps;
target_ups = opts.ups;
this.gameLogic = gameLogic;
this.render = new Render();
this.world = new World();
gameLogic.init(window, world, render);
this.running = true;
}
private void cleanup() {
this.gameLogic.cleanup();
this.render.cleanup();
this.world.cleanup();
this.window.cleanup();
}
private void resize() {
}
private void run() {
long initialTime = System.currentTimeMillis();
float timeU = 1000.0f / target_ups;
float timeR = target_fps > 0 ? 1000.0f / target_fps : 0;
float deltaUpdate = 0;
float deltaFps = 0;
long updateTime = initialTime;
while (running && !window.windowShouldClose()) {
window.pollEvents();
long now = System.currentTimeMillis();
deltaUpdate += (now - initialTime) / timeU;
deltaFps += (now - initialTime) / timeR;
if (target_fps <= 0 || deltaFps >= 1) {
gameLogic.input(window, world, now - initialTime);
}
if (deltaUpdate >= 1) {
long diffTimeMillis = now - updateTime;
gameLogic.update(window, world, diffTimeMillis);
updateTime = now;
deltaUpdate--;
}
if (target_fps <= 0 || deltaFps >= 1) {
render.render(window, world);
deltaFps--;
window.update();
}
initialTime = now;
}
cleanup();
}
public void start() {
running = true;
run();
}
public void stop() {
running = false;
}
}
+54
View File
@@ -0,0 +1,54 @@
package org.xfe.engine;
import java.util.Scanner;
public class Entity
{
Mesh mesh;
public ShaderProgram shader;
public Entity(String object_file_path, String fragment_shader_path, String vertex_shader_path)
{
this.mesh = new Mesh(object_file_path);
// Load Shaders
try {
this.shader = new ShaderProgram();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
String vertex_shader_code = new Scanner(this.getClass().getResourceAsStream(vertex_shader_path)).useDelimiter("\\Z").next();
this.shader.createVertexShader(vertex_shader_code);
} catch (Exception e) {
System.out.println("ERROR Initializing the vertex shader");
e.printStackTrace();
}
try {
String fragment_shader_code = new Scanner(this.getClass().getResourceAsStream(fragment_shader_path)).useDelimiter("\\Z").next();
this.shader.createFragmentShader(fragment_shader_code);
} catch (Exception e)
{
System.out.println("ERROR Initializing the fragment shader");
e.printStackTrace();
}
try {
shader.link();
} catch (Exception e) {
System.out.println("Error linking shader program");
e.printStackTrace();
}
try {
shader.createUniform("projection");
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,11 @@
package org.xfe.engine;
public interface GameLogic {
void cleanup();
void init(Window window, World world, Render render);
void input(Window window, World world, long diffTimeMillis);
void update(Window window, World world, long diffTimeMillis);
}
+17
View File
@@ -0,0 +1,17 @@
package org.xfe.engine;
import org.joml.Vector3f;
public class Light {
Vector3f position;
float power;
Vector3f color;
public Light(Vector3f position, float power, Vector3f color) {
this.position = position;
this.power = power;
this.color = color;
}
}
+151
View File
@@ -0,0 +1,151 @@
package org.xfe.engine;
import org.apache.commons.lang3.ArrayUtils;
import org.lwjgl.system.MemoryUtil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Scanner;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
public class Mesh {
public int vertex_count;
public int vao_id;
public int vbo_id;
public int ebo_id;
Float[] vertices;
Float[] normals;
Integer[] vertice_indices;
Integer[] normal_indices;
// Creates a new Mesh object from an wavefront .obj file
public Mesh(String obj_file_path) {
this.loadObj(obj_file_path);
}
public void loadObj(String file_path) {
ArrayList<Float> temp_vertices = new ArrayList<>();
ArrayList<Float> temp_normals = new ArrayList<>();
ArrayList<Integer> temp_vertice_indices = new ArrayList<>();
ArrayList<Integer> temp_normal_indices = new ArrayList<>();
Scanner scanner;
InputStream obj;
String line;
String[] face_data_temp;
int[] face_data = new int[3];
int i;
// Try to open the file
try {
obj = this.getClass().getResourceAsStream(file_path);
scanner = new Scanner(obj);
} catch (Exception e) {
System.out.println("ERROR: OBJ File \"" + file_path + "\" not found.");
e.printStackTrace();
return;
}
while (scanner.hasNextLine()) {
line = scanner.nextLine();
String[] data = line.split(" ");
switch (data[0]) {
case "v":
temp_vertices.add(Float.valueOf(data[1]));
temp_vertices.add(Float.valueOf(data[2]));
temp_vertices.add(Float.valueOf(data[3]));
break;
case "vn":
temp_normals.add(Float.valueOf(data[1]));
temp_normals.add(Float.valueOf(data[2]));
temp_normals.add(Float.valueOf(data[3]));
break;
case "f":
// Sample face data : "f 5//1 3//1 1//1" where each thing is v//normal_v
for (i = 1; i < 4; i++) {
face_data_temp = data[i].split("//");
temp_vertice_indices.add(Integer.parseInt(face_data_temp[0]));
if (face_data_temp.length > 1)
temp_normal_indices.add(Integer.parseInt(face_data_temp[1]));
}
break;
}
}
this.vertices = temp_vertices.toArray(Float[]::new);
this.normals = temp_normals.toArray(Float[]::new);
this.vertice_indices = temp_vertice_indices.toArray(Integer[]::new);
this.normal_indices = temp_normal_indices.toArray(Integer[]::new);
// OBJ File has been read, setup openGL buffers
init();
}
private void init() {
FloatBuffer vertices_buffer = null;
try {
// Bind our vertices into the VBO
vertices_buffer = MemoryUtil.memAllocFloat(this.vertices.length);
vertex_count = this.vertices.length / 3;
// Convert from our object list to the primitive float array
vertices_buffer.put(ArrayUtils.toPrimitive(this.vertices));
this.vao_id = glGenVertexArrays();
glBindVertexArray(this.vao_id);
this.vbo_id = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, this.vbo_id);
glBufferData(GL_ARRAY_BUFFER, vertices_buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Bind indices in EBO
if (this.vertice_indices.length > 0)
{
// TODO : @0x01fe probably should free this (memory leaks are like bad or smthng)
IntBuffer indice_buffer = MemoryUtil.memAllocInt(vertice_indices.length);
indice_buffer.put(ArrayUtils.toPrimitive(vertice_indices));
ebo_id = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indice_buffer, GL_STATIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
} finally {
if (vertices_buffer != null) {
MemoryUtil.memFree(vertices_buffer);
}
}
}
public void cleanUp() {
glDisableVertexAttribArray(0);
// Delete the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(this.vbo_id);
// Delete the VAO
glBindVertexArray(0);
glDeleteVertexArrays(this.vao_id);
}
}
+50
View File
@@ -0,0 +1,50 @@
package org.xfe.engine;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
public class Render {
private Matrix4f projection_matrix;
public Render() {
GL.createCapabilities();
}
public void cleanup() {
// Nothing to be done here yet
}
public void render(Window window, World world) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(window.getWindowHandle());
float aspect_ratio = (float) window.getWidth() / window.getHeight();
projection_matrix = new Matrix4f().perspective(Engine.FOV, aspect_ratio, Engine.Z_FAR, Engine.Z_NEAR);
for (Entity entity : world.entities) {
entity.shader.bind();
entity.shader.setUniform("projection", projection_matrix);
// entity.shader.setUniform("model", new Matrix4f().identity());
// entity.shader.setUniform("view", new Matrix4f().identity());
// entity.shader.setUniform("lightPos", world.lights.get(0).position);
// entity.shader.setUniform("light_power", world.lights.get(0).power);
// entity.shader.setUniform("lightColor", world.lights.get(0).color);
// entity.shader.setUniform("objectColor", new Vector3f(1.0f, 1.0f, 1.0f));
// entity.shader.setUniform("viewPos", new Vector3f(0.0f, 0.0f, 0.0f));
glBindVertexArray(entity.mesh.ebo_id);
glEnableVertexAttribArray(0);
// glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, entity.mesh.vertice_indices.length, GL_UNSIGNED_INT, 0);
}
}
}
@@ -0,0 +1,121 @@
package org.xfe.engine;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.system.MemoryStack;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.lwjgl.opengl.GL20.*;
public class ShaderProgram {
private final int programId;
private final Map<String, Integer> uniforms;
private int vertexShaderId;
private int fragmentShaderId;
public ShaderProgram() throws Exception {
uniforms = new HashMap<>();
programId = glCreateProgram();
if (programId == 0) {
throw new Exception("Could not create Shader");
}
}
public void createVertexShader(String shaderCode) throws Exception {
vertexShaderId = createShader(shaderCode, GL_VERTEX_SHADER);
}
public void createFragmentShader(String shaderCode) throws Exception {
fragmentShaderId = createShader(shaderCode, GL_FRAGMENT_SHADER);
}
protected int createShader(String shaderCode, int shaderType) throws Exception {
int shaderId = glCreateShader(shaderType);
if (shaderId == 0) {
throw new Exception("Error creating shader. Type: " + shaderType);
}
glShaderSource(shaderId, shaderCode);
glCompileShader(shaderId);
if (glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
throw new Exception("Error compiling Shader code: " + glGetShaderInfoLog(shaderId, 1024));
}
glAttachShader(programId, shaderId);
return shaderId;
}
public void link() throws Exception {
glLinkProgram(programId);
if (glGetProgrami(programId, GL_LINK_STATUS) == 0) {
throw new Exception("Error linking Shader code: " + glGetProgramInfoLog(programId, 1024));
}
if (vertexShaderId != 0) {
glDetachShader(programId, vertexShaderId);
}
if (fragmentShaderId != 0) {
glDetachShader(programId, fragmentShaderId);
}
glValidateProgram(programId);
if (glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
System.err.println("Warning validating Shader code: " + glGetProgramInfoLog(programId, 1024));
}
}
public void bind() {
glUseProgram(programId);
}
public void unbind() {
glUseProgram(0);
}
public void cleanup() {
unbind();
if (programId != 0) {
glDeleteProgram(programId);
}
}
// Set stuff
public void createUniform(String uniform_name) throws Exception {
int uniform_location = glGetUniformLocation(this.programId, uniform_name);
if (uniform_location < 0)
throw new Exception("Could not find uniform: " + uniform_name);
uniforms.put(uniform_name, uniform_location);
}
public void setUniform(String uniform_name, Matrix4f value) {
// Dump the matrix into a float buffer
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer floatBuffer = stack.mallocFloat(16);
value.get(floatBuffer);
glUniformMatrix4fv(uniforms.get(uniform_name), false, floatBuffer);
}
}
public void setUniform(String uniform_name, float value) {
glUniform1f(uniforms.get(uniform_name), value);
}
public void setUniform(String uniform_name, Vector3f value) {
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer floatBuffer = stack.mallocFloat(3);
value.get(floatBuffer);
glUniform3fv(uniforms.get(uniform_name), floatBuffer);
}
}
}
+137
View File
@@ -0,0 +1,137 @@
package org.xfe.engine;
import org.lwjgl.glfw.*;
import java.util.concurrent.Callable;
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.NULL;
public class Window {
private final long windowHandle;
private int height;
private Callable<Void> resizeFunc;
private int width;
public Window(String title, WindowOptions opts, Callable<Void> resizeFunc) {
this.resizeFunc = resizeFunc;
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
if (opts.compatibleProfile) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
} else {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
}
if (opts.width > 0 && opts.height > 0) {
this.width = opts.width;
this.height = opts.height;
} else {
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
width = vidMode.width();
height = vidMode.height();
}
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
if (windowHandle == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
glfwSetFramebufferSizeCallback(windowHandle, (window, w, h) -> resized(w, h));
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
keyCallBack(key, action);
});
glfwMakeContextCurrent(windowHandle);
if (opts.fps > 0) {
glfwSwapInterval(0);
} else {
glfwSwapInterval(1);
}
glfwShowWindow(windowHandle);
int[] arrWidth = new int[1];
int[] arrHeight = new int[1];
glfwGetFramebufferSize(windowHandle, arrWidth, arrHeight);
width = arrWidth[0];
height = arrHeight[0];
}
public void cleanup() {
glfwFreeCallbacks(windowHandle);
glfwDestroyWindow(windowHandle);
glfwTerminate();
GLFWErrorCallback callback = glfwSetErrorCallback(null);
if (callback != null) {
callback.free();
}
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public long getWindowHandle() {
return windowHandle;
}
public boolean isKeyPressed(int keyCode) {
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
}
public void keyCallBack(int key, int action) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
glfwSetWindowShouldClose(windowHandle, true); // We will detect this in the rendering loop
}
}
public void pollEvents() {
glfwPollEvents();
}
protected void resized(int width, int height) {
this.width = width;
this.height = height;
try {
resizeFunc.call();
} catch (Exception excp) {
excp.printStackTrace();
}
}
public void update() {
glfwSwapBuffers(windowHandle);
}
public boolean windowShouldClose() {
return glfwWindowShouldClose(windowHandle);
}
public static class WindowOptions {
public boolean compatibleProfile;
public int fps;
public int height;
public int ups = Engine.TARGET_UPS;
public int width;
}
}
+29
View File
@@ -0,0 +1,29 @@
package org.xfe.engine;
import org.joml.Vector3f;
import java.util.ArrayList;
public class World
{
ArrayList<Entity> entities;
ArrayList<Light> lights;
public World()
{
this.entities = new ArrayList<>();
this.lights = new ArrayList<>();
}
public void addEntity(Entity e)
{
this.entities.add(e);
}
public void addLight(Light l) {
this.lights.add(l);
}
public void cleanup() {}
}
+33
View File
@@ -0,0 +1,33 @@
package org.xfe.game;
import org.xfe.engine.*;
public class Main implements GameLogic {
public static void main(String[] args) {
Main main = new Main();
Engine engine = new Engine("Test", new Window.WindowOptions(), main);
engine.start();
}
@Override
public void cleanup() {
}
@Override
public void init(Window window, World world, Render render) {
Entity cube = new Entity("/objs/cube.obj", "/shaders/shader.frag", "/shaders/shader.vert");
world.addEntity(cube);
}
@Override
public void input(Window window, World world, long diffTimeMillis) {
}
@Override
public void update(Window window, World world, long diffTimeMillis) {
}
}