Add files via upload
This commit is contained in:
parent
267883fb07
commit
032471dda2
56
src/engineTester/MainGameLoop.java
Normal file
56
src/engineTester/MainGameLoop.java
Normal file
@ -0,0 +1,56 @@
|
||||
package engineTester;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import renderEngine.DisplayManager;
|
||||
import renderEngine.Loader;
|
||||
import renderEngine.RawModel;
|
||||
import renderEngine.Renderer;
|
||||
|
||||
/**
|
||||
* This class contains the main method and is used to test the engine.
|
||||
*
|
||||
* @author Karl
|
||||
*
|
||||
*/
|
||||
public class MainGameLoop {
|
||||
|
||||
|
||||
/**
|
||||
* Loads up the position data for two triangles (which together make a quad)
|
||||
* into a VAO. This VAO is then rendered to the screen every frame.
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
DisplayManager.createDisplay();
|
||||
Loader loader = new Loader();
|
||||
Renderer renderer = new Renderer();
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
while (!Display.isCloseRequested()) {
|
||||
// game logic
|
||||
renderer.prepare();
|
||||
renderer.render(model);
|
||||
DisplayManager.updateDisplay();
|
||||
}
|
||||
|
||||
loader.cleanUp();
|
||||
DisplayManager.closeDisplay();
|
||||
}
|
||||
|
||||
}
|
60
src/renderEngine/DisplayManager.java
Normal file
60
src/renderEngine/DisplayManager.java
Normal file
@ -0,0 +1,60 @@
|
||||
package renderEngine;
|
||||
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
|
||||
/**
|
||||
* This class contains all the methods needed to set-up, maintain, and close a LWJGL display.
|
||||
*
|
||||
* @author Karl
|
||||
*
|
||||
*/
|
||||
public class DisplayManager {
|
||||
|
||||
private static final int WIDTH = 1280;
|
||||
private static final int HEIGHT = 720;
|
||||
private static final int FPS_CAP = 60;
|
||||
private static final String TITLE = "Our First Display";
|
||||
|
||||
/**
|
||||
* Creates a display window on which we can render our game. The dimensions
|
||||
* of the window are determined by setting the display mode. By using
|
||||
* "glViewport" we tell OpenGL which part of the window we want to render
|
||||
* our game onto. We indicated that we want to use the entire window.
|
||||
*/
|
||||
public static void createDisplay() {
|
||||
ContextAttribs attribs = new ContextAttribs(3, 2).withForwardCompatible(true).withProfileCore(true);
|
||||
try {
|
||||
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
|
||||
Display.create(new PixelFormat(), attribs);
|
||||
Display.setTitle(TITLE);
|
||||
} catch (LWJGLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
GL11.glViewport(0, 0, WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to update the display at the end of every frame. When
|
||||
* we have set up a rendering process this method will display whatever
|
||||
* we've been rendering onto the screen. The "sync" method is used here to
|
||||
* cap the frame rate. Without this the computer would just try to run the
|
||||
* game as fast as it possibly can, doing more work than it needs to.
|
||||
*/
|
||||
public static void updateDisplay() {
|
||||
Display.sync(FPS_CAP);
|
||||
Display.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* This closes the window when the game is closed.
|
||||
*/
|
||||
public static void closeDisplay() {
|
||||
Display.destroy();
|
||||
}
|
||||
|
||||
}
|
213
src/renderEngine/Loader.java
Normal file
213
src/renderEngine/Loader.java
Normal file
@ -0,0 +1,213 @@
|
||||
package renderEngine;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
/**
|
||||
* Handles the loading of geometry data into VAOs. It also keeps track of all
|
||||
* the created VAOs and VBOs so that they can all be deleted when the game
|
||||
* closes.
|
||||
*
|
||||
* @author Karl
|
||||
*
|
||||
*/
|
||||
public class Loader {
|
||||
|
||||
private List<Integer> vaos = new ArrayList<Integer>();
|
||||
private List<Integer> vbos = new ArrayList<Integer>();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* VAO.
|
||||
*
|
||||
* @param positions
|
||||
* - The 3D positions of each vertex in the geometry (in this
|
||||
* example a quad).
|
||||
* @param indices
|
||||
* - The indices of the model that we want to store in the VAO.
|
||||
* The indices indicate how the vertices should be connected
|
||||
* together to form triangles.
|
||||
* @return The loaded model.
|
||||
*/
|
||||
|
||||
public RawModel loadToVAO(float[] positions, int[] indices) {
|
||||
int vaoID = createVAO();
|
||||
bindIndicesBuffer(indices);
|
||||
storeDataInAttributeList(0, positions);
|
||||
unbindVAO();
|
||||
return new RawModel(vaoID, indices.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all the VAOs and VBOs when the game is closed. VAOs and VBOs are
|
||||
* located in video memory.
|
||||
*/
|
||||
public void cleanUp() {
|
||||
for (int vao : vaos) {
|
||||
GL30.glDeleteVertexArrays(vao);
|
||||
}
|
||||
for (int vbo : vbos) {
|
||||
GL15.glDeleteBuffers(vbo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new VAO and returns its ID. A VAO holds geometry data that we
|
||||
* can render and is physically stored in memory on the GPU, so that it can
|
||||
* be accessed very quickly during rendering.
|
||||
*
|
||||
* Like most objects in OpenGL, the new VAO is created using a "gen" method
|
||||
* which returns the ID of the new VAO. In order to use the VAO it needs to
|
||||
* be made the active VAO. Only one VAO can be active at a time. To make
|
||||
* this VAO the active VAO (so that we can store stuff in it) we have to
|
||||
* bind it.
|
||||
*
|
||||
* @return The ID of the newly created VAO.
|
||||
*/
|
||||
private int createVAO() {
|
||||
int vaoID = GL30.glGenVertexArrays();
|
||||
vaos.add(vaoID);
|
||||
GL30.glBindVertexArray(vaoID);
|
||||
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) {
|
||||
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);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds the VAO after we're finished using it. If we want to edit or use
|
||||
* the VAO we would have to bind it again first.
|
||||
*/
|
||||
private void unbindVAO() {
|
||||
GL30.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an index buffer, binds the index buffer to the currently active
|
||||
* VAO, and then fills it with our indices.
|
||||
*
|
||||
* The index buffer is different from other data that we might store in the
|
||||
* attributes of the VAO. When we stored the positions we were storing data
|
||||
* about each vertex. The positions were "attributes" of each vertex. Data
|
||||
* like that is stored in an attribute list of the VAO.
|
||||
*
|
||||
* The index buffer however does not contain data about each vertex. Instead
|
||||
* it tells OpenGL how the vertices should be connected. Each VAO can only
|
||||
* have one index buffer associated with it. This is why we don't store the
|
||||
* index buffer in a certain attribute of the VAO; each VAO has one special
|
||||
* "slot" for an index buffer and simply binding the index buffer binds it
|
||||
* to the currently active VAO. When the VAO is rendered it will use the
|
||||
* index buffer that is bound to it.
|
||||
*
|
||||
* This is also why we don't unbind the index buffer, as that would unbind
|
||||
* it from the VAO.
|
||||
*
|
||||
* Note that we tell OpenGL that this is an index buffer by using
|
||||
* "GL_ELEMENT_ARRAY_BUFFER" instead of "GL_ARRAY_BUFFER". This is how
|
||||
* OpenGL knows to bind it as the index buffer for the current VAO.
|
||||
*
|
||||
* @param indices
|
||||
*/
|
||||
private void bindIndicesBuffer(int[] indices) {
|
||||
int vboId = GL15.glGenBuffers();
|
||||
vbos.add(vboId);
|
||||
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboId);
|
||||
IntBuffer buffer = storeDataInIntBuffer(indices);
|
||||
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the indices from an int array to an IntBuffer so that they can
|
||||
* be stored in a VBO. Very similar to the storeDataInFloatBuffer() method
|
||||
* below.
|
||||
*
|
||||
* @param data
|
||||
* - The indices in an int[].
|
||||
* @return The indices in a buffer.
|
||||
*/
|
||||
private IntBuffer storeDataInIntBuffer(int[] data) {
|
||||
IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
|
||||
buffer.put(data);
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before we can store data in a VBO it needs to be in a certain format: in
|
||||
* a buffer. In this case we will use a float buffer because the data we
|
||||
* want to store is float data. If we were storing int data we would use an
|
||||
* IntBuffer.
|
||||
*
|
||||
* First and empty buffer of the correct size is created. You can think of a
|
||||
* buffer as basically an array with a pointer. After putting the necessary
|
||||
* data into the buffer the pointer will have increased so that it points at
|
||||
* the first empty element of the array. This is so that we could add more
|
||||
* data to the buffer if we wanted and it wouldn't overwrite the data we've
|
||||
* already put in. However, we're done with storing data and we want to make
|
||||
* the buffer ready for reading. To do this we need to make the pointer
|
||||
* point to the start of the data, so that OpenGL knows where in the buffer
|
||||
* to start reading. The "flip()" method does just that, putting the pointer
|
||||
* back to the start of the buffer.
|
||||
*
|
||||
* @param data
|
||||
* - The float data that is going to be stored in the buffer.
|
||||
* @return The FloatBuffer containing the data. This float buffer is ready
|
||||
* to be loaded into a VBO.
|
||||
*/
|
||||
private FloatBuffer storeDataInFloatBuffer(float[] data) {
|
||||
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
|
||||
buffer.put(data);
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
35
src/renderEngine/RawModel.java
Normal file
35
src/renderEngine/RawModel.java
Normal file
@ -0,0 +1,35 @@
|
||||
package renderEngine;
|
||||
|
||||
/**
|
||||
* Represents a loaded model. It contains the ID of the VAO that contains the
|
||||
* model's data, and holds the number of vertices in the model.
|
||||
*
|
||||
* @author Karl
|
||||
*
|
||||
*/
|
||||
public class RawModel {
|
||||
|
||||
private int vaoID;
|
||||
private int vertexCount;
|
||||
|
||||
public RawModel(int vaoID, int vertexCount) {
|
||||
this.vaoID = vaoID;
|
||||
this.vertexCount = vertexCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ID of the VAO which contains the data about all the geometry
|
||||
* of this model.
|
||||
*/
|
||||
public int getVaoID() {
|
||||
return vaoID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of vertices in the model.
|
||||
*/
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
}
|
58
src/renderEngine/Renderer.java
Normal file
58
src/renderEngine/Renderer.java
Normal file
@ -0,0 +1,58 @@
|
||||
package renderEngine;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
/**
|
||||
* Handles the rendering of a model to the screen.
|
||||
*
|
||||
* @author Karl
|
||||
*
|
||||
*/
|
||||
public class Renderer {
|
||||
|
||||
/**
|
||||
* This method must be called each frame, before any rendering is carried
|
||||
* out. It basically clears the screen of everything that was rendered last
|
||||
* frame (using the glClear() method). The glClearColor() method determines
|
||||
* the colour that it uses to clear the screen. In this example it makes the
|
||||
* entire screen red at the start of each frame.
|
||||
*/
|
||||
public void prepare() {
|
||||
GL11.glClearColor(1, 0, 0, 1);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a model to the screen.
|
||||
*
|
||||
* Before we can render a VAO it needs to be made active, and we can do this
|
||||
* by binding it. We also need to enable the relevant attributes of the VAO,
|
||||
* which in this case is just attribute 0 where we stored the position data.
|
||||
*
|
||||
* The VAO can then be rendered to the screen using glDrawElements(). Using
|
||||
* this draw method tells OpenGL that we want to use the index buffer to
|
||||
* determine how the vertices should be connected instead of just connecting
|
||||
* the vertices together in the order that they are stored in the VAO.
|
||||
*
|
||||
* We tell it what type of shapes to render and the number of vertices that
|
||||
* it needs to render. We also tell it was format the index data is in (we
|
||||
* used ints) and finally we indicate where in the index buffer it should
|
||||
* start rendering. We want it to start right at the beginning and render
|
||||
* everything, so we put 0.
|
||||
*
|
||||
* After rendering we unbind the VAO and disable the attribute.
|
||||
*
|
||||
* @param model
|
||||
* - The model to be rendered.
|
||||
*/
|
||||
public void render(RawModel model) {
|
||||
GL30.glBindVertexArray(model.getVaoID());
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
|
||||
GL20.glDisableVertexAttribArray(0);
|
||||
GL30.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user