diff --git a/src/main/java/com/okseby/core/ObjectLoader.java b/src/main/java/com/okseby/core/ObjectLoader.java index 55eff3e..327c43c 100644 --- a/src/main/java/com/okseby/core/ObjectLoader.java +++ b/src/main/java/com/okseby/core/ObjectLoader.java @@ -6,7 +6,10 @@ import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; +import org.lwjgl.stb.STBImage; +import org.lwjgl.system.MemoryStack; +import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; @@ -15,14 +18,45 @@ import java.util.List; public class ObjectLoader { private List vaos = new ArrayList<>(); private List vbos = new ArrayList<>(); + private List textures = new ArrayList<>(); - public Model loadModel(float[] vertices, int[] indices) { + public Model loadModel(float[] vertices, float[] textureCoordinates, int[] indices) { int id = createVAO(); storeIndicesBuffer(indices); storeDataInAttributeList(0, 3, vertices); + storeDataInAttributeList(1, 2, textureCoordinates); unbind(); - return new Model(id, vertices.length / 3); + return new Model(id, indices.length); + } + + public int loadTexture(String filename) throws Exception { + int width, height; + ByteBuffer buffer; + + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer w = stack.mallocInt(1); + IntBuffer h = stack.mallocInt(1); + IntBuffer c = stack.mallocInt(1); + + buffer = STBImage.stbi_load(filename, w, h, c, 4); + if (buffer == null) + throw new Exception("Image File " + filename + " not loaded " + STBImage.stbi_failure_reason()); + + width = w.get(); + height = h.get(); + } + + int id = GL11.glGenTextures(); + + textures.add(id); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, id); + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + STBImage.stbi_image_free(buffer); + + return id; } private int createVAO() { @@ -67,5 +101,7 @@ public class ObjectLoader { GL30.glDeleteVertexArrays(vao); for (int vbo : vbos) GL30.glDeleteBuffers(vbo); + for (int texture : textures) + GL11.glDeleteTextures(texture); } } diff --git a/src/main/java/com/okseby/core/RenderManager.java b/src/main/java/com/okseby/core/RenderManager.java index 1becf6d..8110eeb 100644 --- a/src/main/java/com/okseby/core/RenderManager.java +++ b/src/main/java/com/okseby/core/RenderManager.java @@ -3,6 +3,7 @@ package com.okseby.core; import com.okseby.core.entity.Model; import com.okseby.core.utils.Utils; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; @@ -21,18 +22,25 @@ public class RenderManager { shader.createFragmentShader(Utils.loadResource("/shaders/fragment.fs")); shader.link(); + shader.createUniform("textureSampler"); } public void render(Model model) { clear(); shader.bind(); + shader.setUniform("textureSampler", 0); GL30.glBindVertexArray(model.getId()); GL20.glEnableVertexAttribArray(0); - GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount()); + GL20.glEnableVertexAttribArray(1); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, model.getTexture().getId()); + GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0); GL20.glDisableVertexAttribArray(0); + GL20.glDisableVertexAttribArray(1); + GL30.glBindVertexArray(0); shader.unbind(); diff --git a/src/main/java/com/okseby/core/ShaderManager.java b/src/main/java/com/okseby/core/ShaderManager.java index 5a4a4cc..f0fce34 100644 --- a/src/main/java/com/okseby/core/ShaderManager.java +++ b/src/main/java/com/okseby/core/ShaderManager.java @@ -1,15 +1,42 @@ package com.okseby.core; +import org.joml.Matrix4f; import org.lwjgl.opengl.GL20; +import org.lwjgl.system.MemoryStack; + +import java.util.HashMap; +import java.util.Map; public class ShaderManager { private final int programID; private int vertexShaderID, fragmentShaderID; + private final Map uniforms; + public ShaderManager() throws Exception { programID = GL20.glCreateProgram(); if (programID == 0) throw new Exception("Could not create shader"); + + uniforms = new HashMap<>(); + } + + public void createUniform(String uniformName) throws Exception { + int uniformLocation = GL20.glGetUniformLocation(programID, uniformName); + if (uniformLocation < 0) + throw new Exception("Could not find uniform " + uniformName); + + uniforms.put(uniformName, uniformLocation); + } + + public void setUniform(String uniformName, Matrix4f value) { + try (MemoryStack stack = MemoryStack.stackPush()) { + GL20.glUniformMatrix4fv(uniforms.get(uniformName), false, value.get(stack.mallocFloat(16))); + } + } + + public void setUniform(String uniformName, int value) { + GL20.glUniform1i(uniforms.get(uniformName), value); } public void createVertexShader(String shaderCode) throws Exception { diff --git a/src/main/java/com/okseby/core/WindowManager.java b/src/main/java/com/okseby/core/WindowManager.java index 0c3afca..d37d572 100644 --- a/src/main/java/com/okseby/core/WindowManager.java +++ b/src/main/java/com/okseby/core/WindowManager.java @@ -17,9 +17,10 @@ public class WindowManager { @Getter private long window; @Getter private int width, height; + @Getter private final Matrix4f projectionMatrix; + @Getter @Setter private String title; @Getter @Setter private boolean resizeable, vsync; - @Getter private final Matrix4f projectionMatrix; public WindowManager(String title, int width, int height, boolean vsync) { this.title = title; diff --git a/src/main/java/com/okseby/core/entity/Model.java b/src/main/java/com/okseby/core/entity/Model.java index 754d02c..55d5532 100644 --- a/src/main/java/com/okseby/core/entity/Model.java +++ b/src/main/java/com/okseby/core/entity/Model.java @@ -1,13 +1,28 @@ package com.okseby.core.entity; import lombok.Getter; +import lombok.Setter; public class Model { @Getter private int id; @Getter private int vertexCount; + @Getter @Setter private Texture texture; + public Model(int id, int vertexCount) { this.id = id; this.vertexCount = vertexCount; } + + public Model(int id, int vertexCount, Texture texture) { + this.id = id; + this.vertexCount = vertexCount; + this.texture = texture; + } + + public Model(Model model, Texture texture) { + this.id = model.getId(); + this.vertexCount = model.getVertexCount(); + this.texture = texture; + } } diff --git a/src/main/java/com/okseby/core/entity/Texture.java b/src/main/java/com/okseby/core/entity/Texture.java new file mode 100644 index 0000000..f81ef9e --- /dev/null +++ b/src/main/java/com/okseby/core/entity/Texture.java @@ -0,0 +1,14 @@ +package com.okseby.core.entity; + +import lombok.Getter; + +public class Texture { + + @Getter private final int id; + + public Texture(int id) { + this.id = id; + } + + +} diff --git a/src/main/java/com/okseby/core/test/TestGame.java b/src/main/java/com/okseby/core/test/TestGame.java index a01c465..28b56c8 100644 --- a/src/main/java/com/okseby/core/test/TestGame.java +++ b/src/main/java/com/okseby/core/test/TestGame.java @@ -2,6 +2,7 @@ package com.okseby.core.test; import com.okseby.core.*; import com.okseby.core.entity.Model; +import com.okseby.core.entity.Texture; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.GL11; @@ -29,9 +30,7 @@ public class TestGame implements ILogic { -0.5f, 0.5f, 0f, -0.5f, -0.5f, 0f, 0.5f, -0.5f, 0f, - 0.5f, -0.5f, 0f, 0.5f, 0.5f, 0f, - -0.5f, 0.5f, 0f }; int[] indices = { @@ -39,7 +38,15 @@ public class TestGame implements ILogic { 3, 1, 2 }; - model = loader.loadModel(vertices, indices); + float[] textureCoordinates = { + 0, 0, + 0, 1, + 1, 1, + 1, 0 + }; + + model = loader.loadModel(vertices, textureCoordinates, indices); + model.setTexture(new Texture(loader.loadTexture("textures/grassblock.png"))); } @Override diff --git a/src/main/resources/shaders/fragment.fs b/src/main/resources/shaders/fragment.fs index 9cd2af0..a1e9c74 100644 --- a/src/main/resources/shaders/fragment.fs +++ b/src/main/resources/shaders/fragment.fs @@ -1,9 +1,11 @@ #version 400 core -in vec3 color; +in vec2 fragmentTextureCoordinates; out vec4 fragmentColor; +uniform sampler2D textureSampler; + void main() { - fragmentColor = vec4(color, 1.0); + fragmentColor = texture(textureSampler, fragmentTextureCoordinates); } \ No newline at end of file diff --git a/src/main/resources/shaders/vertex.vs b/src/main/resources/shaders/vertex.vs index 748fa9c..7881ae5 100644 --- a/src/main/resources/shaders/vertex.vs +++ b/src/main/resources/shaders/vertex.vs @@ -1,10 +1,11 @@ #version 400 core in vec3 position; +in vec2 textureCoordinates; -out vec3 color; +out vec2 fragmentTextureCoordinates; void main() { gl_Position = vec4(position, 1.0); - color = vec3(position.x + 0.25, 0.17, position.y + 0.25); + fragmentTextureCoordinates = textureCoordinates; } \ No newline at end of file diff --git a/textures/grassblock.png b/textures/grassblock.png new file mode 100644 index 0000000..5d44b71 Binary files /dev/null and b/textures/grassblock.png differ