diff --git a/.classpath b/.classpath index bfd5adc..f580185 100644 --- a/.classpath +++ b/.classpath @@ -805,5 +805,10 @@ + + + + + diff --git a/lib/pngdecoder.jar b/lib/pngdecoder.jar new file mode 100644 index 0000000..fc39e9b Binary files /dev/null and b/lib/pngdecoder.jar differ diff --git a/res/tree_sample.png b/res/tree_sample.png new file mode 100644 index 0000000..eab9219 Binary files /dev/null and b/res/tree_sample.png differ diff --git a/src/engineTester/MainGameLoop.java b/src/engineTester/MainGameLoop.java index ccc34b2..770aa38 100644 --- a/src/engineTester/MainGameLoop.java +++ b/src/engineTester/MainGameLoop.java @@ -1,12 +1,14 @@ package engineTester; +import models.RawModel; +import models.TexturedModel; import renderEngine.DisplayManager; import renderEngine.DisplayManagerDraw; import renderEngine.Loader; -import renderEngine.RawModel; import renderEngine.Renderer; import shaders.StaticShader; +import textures.ModelTexture; /** * This class contains the main method and is used to test the engine. @@ -30,27 +32,35 @@ public class MainGameLoop { Renderer renderer = new Renderer(); manager.init(); StaticShader shader = new StaticShader(); - + float[] vertices = { -0.5f, 0.5f, 0f,//v0 -0.5f, -0.5f, 0f,//v1 0.5f, -0.5f, 0f,//v2 0.5f, 0.5f, 0f,//v3 }; + float[] textureCoords = { + 0.0f, 0.0f,//v0 + 0.0f, 1.0f,//v1 + 1.0f, 1.0f,//v2 + 1.0f, 0.0f,//v3 + }; int[] indices = { 0,1,3,//top left triangle (v0, v1, v3) 3,1,2//bottom right triangle (v3, v1, v2) }; - RawModel model = loader.loadToVAO(vertices, indices); + RawModel model = loader.loadToVAO(vertices, textureCoords, indices); + ModelTexture texture = new ModelTexture(loader.loadTexture("tree_sample")); + TexturedModel texturedModel = new TexturedModel(model, texture); manager.setDrawer(new DisplayManagerDraw() { @Override public void draw() { renderer.prepare(); shader.start(); - renderer.render(model); + renderer.render(texturedModel); shader.stop(); } }); diff --git a/src/renderEngine/RawModel.java b/src/models/RawModel.java similarity index 91% rename from src/renderEngine/RawModel.java rename to src/models/RawModel.java index c36485d..9db98f2 100644 --- a/src/renderEngine/RawModel.java +++ b/src/models/RawModel.java @@ -1,4 +1,4 @@ -package renderEngine; +package models; /** * Represents a loaded model. It contains the ID of the VAO that contains the diff --git a/src/models/TexturedModel.java b/src/models/TexturedModel.java new file mode 100644 index 0000000..caf9d5b --- /dev/null +++ b/src/models/TexturedModel.java @@ -0,0 +1,31 @@ +package models; + +import textures.ModelTexture; + +public class TexturedModel { + + private RawModel rawModel; + private ModelTexture texture; + + public TexturedModel(RawModel model, ModelTexture texture) { + this.rawModel = model; + this.texture = texture; + } + + public RawModel getRawModel() { + return rawModel; + } + + public void setRawModel(RawModel rawModel) { + this.rawModel = rawModel; + } + + public ModelTexture getTexture() { + return texture; + } + + public void setTexture(ModelTexture texture) { + this.texture = texture; + } + +} diff --git a/src/module-info.java b/src/module-info.java index 99a8c51..613a246 100644 --- a/src/module-info.java +++ b/src/module-info.java @@ -17,5 +17,8 @@ open module Tutorial { requires transitive org.lwjgl.stb.natives; requires transitive org.lwjgl.opengl; requires transitive org.lwjgl.opengl.natives; + requires org.lwjgl.openvr; + requires java.desktop; + requires pngdecoder; } diff --git a/src/renderEngine/Loader.java b/src/renderEngine/Loader.java index 9a68c82..9b6c8a6 100644 --- a/src/renderEngine/Loader.java +++ b/src/renderEngine/Loader.java @@ -1,5 +1,9 @@ package renderEngine; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; @@ -7,9 +11,15 @@ import java.util.List; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; +import org.lwjgl.openvr.Texture; + +import de.matthiasmann.twl.utils.PNGDecoder; +import de.matthiasmann.twl.utils.PNGDecoder.Format; +import models.RawModel; /** * Handles the loading of geometry data into VAOs. It also keeps track of all @@ -23,7 +33,20 @@ public class Loader { private List vaos = new ArrayList(); private List vbos = new ArrayList(); - + private List textures = new ArrayList(); + + private void exitOnGLError(String errorMessage) { + int errorValue = GL11.glGetError(); + + if (errorValue != GL11.GL_NO_ERROR) { + System.err.println("ERROR - " + errorMessage + ": ???" ); +// String errorString = GLU.gluErrorString(errorValue); +// System.err.println("ERROR - " + errorMessage + ": " + errorString); +// +// if (Display.isCreated()) Display.destroy(); + System.exit(-1); + } + } /** * Creates a VAO and stores the position data of the vertices into attribute * 0 of the VAO. The indices are stored in an index buffer and bound to the @@ -42,11 +65,75 @@ public class Loader { public RawModel loadToVAO(float[] positions, int[] indices) { int vaoID = createVAO(); bindIndicesBuffer(indices); - storeDataInAttributeList(0, positions); + storeDataInAttributeList(0, 3, positions); unbindVAO(); return new RawModel(vaoID, indices.length); } - + public RawModel loadToVAO(float[] positions, float[] textureCoordinates, int[] indices) { + int vaoID = createVAO(); + bindIndicesBuffer(indices); + storeDataInAttributeList(0, 3, positions); + storeDataInAttributeList(1, 2, textureCoordinates); + unbindVAO(); + return new RawModel(vaoID, indices.length); + } + + public int loadTexture(String filename) { + int textureId = loadPNGTexture("res/" + filename + ".png", GL13.GL_TEXTURE0); + this.textures.add(textureId); + return textureId; + } + + private 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); + + this.exitOnGLError("loadPNGTexture"); + + return texId; + } /** * Deletes all the VAOs and VBOs when the game is closed. VAOs and VBOs are * located in video memory. @@ -58,6 +145,9 @@ public class Loader { for (int vbo : vbos) { GL15.glDeleteBuffers(vbo); } + for (int texture : textures) { + GL11.glDeleteTextures(texture); + } } /** @@ -80,46 +170,13 @@ public class Loader { return vaoID; } - /** - * Stores the position data of the vertices into attribute 0 of the VAO. To - * do this the positions must first be stored in a VBO. You can simply think - * of a VBO as an array of data that is stored in memory on the GPU for easy - * access during rendering. - * - * Just like with the VAO, we create a new VBO using a "gen" method, and - * make it the active VBO (so that we do stuff to it) by binding it. - * - * We then store the positions data in the active VBO by using the - * glBufferData method. We also indicate using GL_STATIC_DRAW that this data - * won't need to be changed. If we wanted to edit the positions every frame - * (perhaps to animate the quad) then we would use GL_DYNAMIC_DRAW instead. - * - * We the connect the VBO to the VAO using the glVertexAttribPointer() - * method. This needs to know the attribute number of the VAO where we want - * to put the data, the number of floats used for each vertex (3 floats in - * this case, because each vertex has a 3D position, an x, y, and z value), - * the type of data (in this case we used floats) and then some other more - * complicated stuff for storing the data in more fancy ways. Don't worry - * about the last 3 parameters for now, we don't need them here. - * - * Now that we've finished using the VBO we can unbind it. This isn't - * totally necessary, but I think it's good practice to unbind the VBO when - * you're done using it. - * - * @param attributeNumber - * - The number of the attribute of the VAO where the data is to - * be stored. - * @param data - * - The geometry data to be stored in the VAO, in this case the - * positions of the vertices. - */ - private void storeDataInAttributeList(int attributeNumber, float[] data) { + private void storeDataInAttributeList(int attributeNumber, int coordinateSize, float[] data) { int vboID = GL15.glGenBuffers(); vbos.add(vboID); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID); FloatBuffer buffer = storeDataInFloatBuffer(data); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); - GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0); + GL20.glVertexAttribPointer(attributeNumber, coordinateSize, GL11.GL_FLOAT, false, 0, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } diff --git a/src/renderEngine/Renderer.java b/src/renderEngine/Renderer.java index e7e67fb..1b08d0e 100644 --- a/src/renderEngine/Renderer.java +++ b/src/renderEngine/Renderer.java @@ -1,9 +1,13 @@ package renderEngine; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; +import models.RawModel; +import models.TexturedModel; + /** * Handles the rendering of a model to the screen. * @@ -54,5 +58,17 @@ public class Renderer { GL20.glDisableVertexAttribArray(0); GL30.glBindVertexArray(0); } + public void render(TexturedModel texturedModel) { + RawModel model = texturedModel.getRawModel(); + GL30.glBindVertexArray(model.getVaoID()); + GL20.glEnableVertexAttribArray(0); + GL20.glEnableVertexAttribArray(1); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getTexturedID()); + GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0); + GL20.glDisableVertexAttribArray(0); + GL20.glDisableVertexAttribArray(1); + GL30.glBindVertexArray(0); + } } diff --git a/src/shaders/StaticShader.java b/src/shaders/StaticShader.java index f6ab20c..ae6d9f9 100644 --- a/src/shaders/StaticShader.java +++ b/src/shaders/StaticShader.java @@ -11,6 +11,7 @@ public class StaticShader extends ShaderProgram { @Override protected void bindAttributes() { super.bindAttribute(0, "position"); + super.bindAttribute(1, "textureCoords"); } } diff --git a/src/shaders/fragmentShader.txt b/src/shaders/fragmentShader.txt index 3920269..d253531 100644 --- a/src/shaders/fragmentShader.txt +++ b/src/shaders/fragmentShader.txt @@ -1,10 +1,12 @@ #version 400 core -in vec3 colour; +in vec2 pass_textureCoords; out vec4 out_Color; +uniform sampler2D textureSampler; + void main(void) { - out_Color = vec4(colour, 1.0); + out_Color = texture(textureSampler,pass_textureCoords); } diff --git a/src/shaders/vertexShader.txt b/src/shaders/vertexShader.txt index 8399bc2..ee4b5e1 100644 --- a/src/shaders/vertexShader.txt +++ b/src/shaders/vertexShader.txt @@ -1,12 +1,13 @@ #version 400 core in vec3 position; +in vec2 textureCoords; -out vec3 colour; +out vec2 pass_textureCoords; void main(void) { gl_Position = vec4(position, 1.0); - colour = vec3(position.x+0.5, 1.0, position.y+0.5); + pass_textureCoords = textureCoords; } diff --git a/src/textures/ModelTexture.java b/src/textures/ModelTexture.java new file mode 100644 index 0000000..eb3520d --- /dev/null +++ b/src/textures/ModelTexture.java @@ -0,0 +1,15 @@ +package textures; + +public class ModelTexture { + + private int textureID; + + public ModelTexture(int id) { + this.textureID = id; + } + + public int getTexturedID() { + return textureID; + } + +}