mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
multi texture rendering, use vbos for rendering
This commit is contained in:
parent
d06bba2eb6
commit
98beee726d
@ -82,4 +82,8 @@ public class Chunk {
|
|||||||
public void setBlockEntityData(HashMap<InChunkLocation, BlockEntityMetaData> blockEntities) {
|
public void setBlockEntityData(HashMap<InChunkLocation, BlockEntityMetaData> blockEntities) {
|
||||||
blockEntities.forEach(this::setBlockEntityData);
|
blockEntities.forEach(this::setBlockEntityData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HashMap<Byte, ChunkSection> getSections() {
|
||||||
|
return this.sections;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering;
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||||
|
import de.bixilon.minosoft.data.world.Chunk;
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class DummyData {
|
||||||
|
private static final Block BEDROCK = new Block("bedrock");
|
||||||
|
private static final Block DIRT = new Block("dirt");
|
||||||
|
|
||||||
|
public static Chunk getDummyChunk() {
|
||||||
|
Chunk chunk = new Chunk(new HashMap<>());
|
||||||
|
for (int y = 0; y < ProtocolDefinition.SECTION_HEIGHT_Y; y++) {
|
||||||
|
for (int x = 0; x < ProtocolDefinition.SECTION_WIDTH_X; x++) {
|
||||||
|
for (int z = 0; z < ProtocolDefinition.SECTION_WIDTH_Z; z++) {
|
||||||
|
if (y == 0) {
|
||||||
|
chunk.setBlock(x, y, z, BEDROCK);
|
||||||
|
} else if (y < 8) {
|
||||||
|
chunk.setBlock(x, y, z, DIRT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
}
|
113
src/main/java/de/bixilon/minosoft/gui/rendering/Mesh.java
Normal file
113
src/main/java/de/bixilon/minosoft/gui/rendering/Mesh.java
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering;
|
||||||
|
|
||||||
|
import glm_.mat4x4.Mat4;
|
||||||
|
import glm_.vec3.Vec3;
|
||||||
|
import glm_.vec4.Vec4;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||||
|
import static org.lwjgl.opengl.GL11.glDrawArrays;
|
||||||
|
import static org.lwjgl.opengl.GL15.glGenBuffers;
|
||||||
|
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||||
|
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||||
|
|
||||||
|
public class Mesh {
|
||||||
|
public static final float[][] VERTICIES = {
|
||||||
|
{
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 1.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 2.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 2.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 3.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 1.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 2.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 2.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, 3.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 2.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 2.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 2.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 1.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 1.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 3.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-0.5f, 0.5f, -0.5f, 3.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 2.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 3.0f,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int textureLayer;
|
||||||
|
int vAO;
|
||||||
|
int vBO;
|
||||||
|
|
||||||
|
public Mesh(int textureLayer, Vec3 position) {
|
||||||
|
this.textureLayer = textureLayer;
|
||||||
|
float[] result = new float[VERTICIES.length * VERTICIES[0].length + (VERTICIES.length * VERTICIES[0].length / 2)];
|
||||||
|
int resultIndex = 0;
|
||||||
|
|
||||||
|
var model = new Mat4().translate(position);
|
||||||
|
|
||||||
|
for (float[] side : VERTICIES) {
|
||||||
|
for (int vertex = 0; vertex < side.length; ) {
|
||||||
|
Vec4 input = new Vec4(side[vertex++], side[vertex++], side[vertex++], 1.0f);
|
||||||
|
var output = model.times(input);
|
||||||
|
// Log.debug("input=%s; position=%s; output=%s;", input, position, output);
|
||||||
|
result[resultIndex++] = output.x;
|
||||||
|
result[resultIndex++] = output.y;
|
||||||
|
result[resultIndex++] = output.z;
|
||||||
|
result[resultIndex++] = side[vertex++];
|
||||||
|
result[resultIndex++] = textureLayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vAO = glGenVertexArrays();
|
||||||
|
this.vBO = glGenBuffers();
|
||||||
|
|
||||||
|
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||||
|
glBindVertexArray(this.vAO);
|
||||||
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vBO);
|
||||||
|
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, result, GL15.GL_STATIC_DRAW);
|
||||||
|
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 5 * Float.BYTES, 0L);
|
||||||
|
GL20.glEnableVertexAttribArray(0);
|
||||||
|
GL20.glVertexAttribPointer(1, 1, GL11.GL_FLOAT, false, 5 * Float.BYTES, 3 * Float.BYTES);
|
||||||
|
GL20.glEnableVertexAttribArray(1);
|
||||||
|
GL20.glVertexAttribPointer(2, 1, GL11.GL_FLOAT, false, 5 * Float.BYTES, 4 * Float.BYTES);
|
||||||
|
GL20.glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
|
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
|
||||||
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw() {
|
||||||
|
glBindVertexArray(this.vAO);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
|
}
|
||||||
|
}
|
@ -1,305 +0,0 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering;
|
|
||||||
|
|
||||||
import de.bixilon.minosoft.gui.rendering.exceptions.ShaderLoadingException;
|
|
||||||
import glm_.glm;
|
|
||||||
import glm_.mat4x4.Mat4;
|
|
||||||
import glm_.vec3.Vec3;
|
|
||||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
|
||||||
import org.lwjgl.glfw.GLFWVidMode;
|
|
||||||
import org.lwjgl.glfw.GLFWWindowSizeCallback;
|
|
||||||
import org.lwjgl.opengl.GL;
|
|
||||||
import org.lwjgl.system.MemoryStack;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
|
|
||||||
import static org.lwjgl.glfw.GLFW.*;
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
import static org.lwjgl.opengl.GL15.*;
|
|
||||||
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
|
|
||||||
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
|
||||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
|
||||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
|
||||||
import static org.lwjgl.system.MemoryStack.stackPush;
|
|
||||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
|
||||||
|
|
||||||
|
|
||||||
public class RenderWindow {
|
|
||||||
private final float[] vertices = {
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
|
|
||||||
};
|
|
||||||
private final Vec3[] cubePositions = {
|
|
||||||
new Vec3(0.0f, 0.0f, 0.0f),
|
|
||||||
new Vec3(2.0f, 5.0f, -15.0f),
|
|
||||||
new Vec3(-1.5f, -2.2f, -2.5f),
|
|
||||||
new Vec3(-3.8f, -2.0f, -12.3f),
|
|
||||||
new Vec3(2.4f, -0.4f, -3.5f),
|
|
||||||
new Vec3(-1.7f, 3.0f, -7.5f),
|
|
||||||
new Vec3(1.3f, -2.0f, -2.5f),
|
|
||||||
new Vec3(1.5f, 2.0f, -2.5f),
|
|
||||||
new Vec3(1.5f, 0.2f, -1.5f),
|
|
||||||
new Vec3(-1.3f, 1.0f, -1.5f)
|
|
||||||
};
|
|
||||||
private int screenWidth = 800;
|
|
||||||
private int screenHeight = 600;
|
|
||||||
private float visibilityLevel;
|
|
||||||
private boolean polygonEnabled;
|
|
||||||
private Shader shader;
|
|
||||||
private Texture texture0;
|
|
||||||
private Texture texture1;
|
|
||||||
private long windowId;
|
|
||||||
|
|
||||||
private double deltaTime; // time between current frame and last frame
|
|
||||||
private double lastFrame;
|
|
||||||
|
|
||||||
private Camera camera;
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
// Setup an error callback. The default implementation
|
|
||||||
// will print the error message in System.err.
|
|
||||||
GLFWErrorCallback.createPrint(System.err).set();
|
|
||||||
|
|
||||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
|
||||||
if (!glfwInit()) {
|
|
||||||
throw new IllegalStateException("Unable to initialize GLFW");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure GLFW
|
|
||||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
||||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
|
|
||||||
|
|
||||||
// Create the window
|
|
||||||
this.windowId = glfwCreateWindow(this.screenWidth, this.screenHeight, "Hello World!", NULL, NULL);
|
|
||||||
if (this.windowId == NULL) {
|
|
||||||
glfwTerminate();
|
|
||||||
throw new RuntimeException("Failed to create the GLFW window");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.camera = new Camera(45f, this.windowId);
|
|
||||||
|
|
||||||
|
|
||||||
glfwSetWindowSizeCallback(this.windowId, new GLFWWindowSizeCallback() {
|
|
||||||
@Override
|
|
||||||
public void invoke(long window, int width, int height) {
|
|
||||||
glViewport(0, 0, width, height);
|
|
||||||
RenderWindow.this.screenWidth = width;
|
|
||||||
RenderWindow.this.screenHeight = height;
|
|
||||||
RenderWindow.this.camera.calculateProjectionMatrix(RenderWindow.this.screenWidth, RenderWindow.this.screenHeight, RenderWindow.this.shader);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
|
||||||
glfwSetKeyCallback(this.windowId, (window, key, scancode, action, mods) -> {
|
|
||||||
if (action != GLFW_RELEASE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (key) {
|
|
||||||
case GLFW_KEY_ESCAPE -> glfwSetWindowShouldClose(this.windowId, true);
|
|
||||||
case GLFW_KEY_P -> switchPolygonMode();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
glfwSetInputMode(this.windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
|
||||||
|
|
||||||
|
|
||||||
glfwSetCursorPosCallback(this.windowId, ((window, xPos, yPos) -> this.camera.mouseCallback(xPos, yPos)));
|
|
||||||
|
|
||||||
|
|
||||||
// Get the thread stack and push a new frame
|
|
||||||
try (MemoryStack stack = stackPush()) {
|
|
||||||
IntBuffer pWidth = stack.mallocInt(1); // int*
|
|
||||||
IntBuffer pHeight = stack.mallocInt(1); // int*
|
|
||||||
|
|
||||||
// Get the window size passed to glfwCreateWindow
|
|
||||||
glfwGetWindowSize(this.windowId, pWidth, pHeight);
|
|
||||||
|
|
||||||
// Get the resolution of the primary monitor
|
|
||||||
GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
|
||||||
|
|
||||||
// Center the window
|
|
||||||
glfwSetWindowPos(this.windowId, (videoMode.width() - pWidth.get(0)) / 2, (videoMode.height() - pHeight.get(0)) / 2);
|
|
||||||
} // the stack frame is popped automatically
|
|
||||||
|
|
||||||
// Make the OpenGL context current
|
|
||||||
glfwMakeContextCurrent(this.windowId);
|
|
||||||
// Enable v-sync
|
|
||||||
glfwSwapInterval(1);
|
|
||||||
|
|
||||||
|
|
||||||
// Make the window visible
|
|
||||||
glfwShowWindow(this.windowId);
|
|
||||||
|
|
||||||
GL.createCapabilities();
|
|
||||||
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startLoop() throws IOException, ShaderLoadingException {
|
|
||||||
int vAO = glGenVertexArrays();
|
|
||||||
int vBO = glGenBuffers();
|
|
||||||
|
|
||||||
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
|
||||||
glBindVertexArray(vAO);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vBO);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, this.vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, 5 * Float.BYTES, 0L);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, 5 * Float.BYTES, (3 * Float.BYTES));
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
|
|
||||||
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
|
|
||||||
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
|
|
||||||
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
this.texture0 = new Texture("/textures/emerald_block.png");
|
|
||||||
this.texture0.load();
|
|
||||||
this.texture1 = new Texture("/textures/brown_wool.png");
|
|
||||||
this.texture1.load();
|
|
||||||
|
|
||||||
this.shader = new Shader("vertex.glsl", "fragment.glsl");
|
|
||||||
this.shader.load();
|
|
||||||
this.shader.use();
|
|
||||||
|
|
||||||
|
|
||||||
this.shader.setInt("texture0", 0);
|
|
||||||
this.shader.setInt("texture1", 1);
|
|
||||||
|
|
||||||
this.shader.setFloat("visibility", this.visibilityLevel);
|
|
||||||
|
|
||||||
this.camera.calculateProjectionMatrix(this.screenWidth, this.screenHeight, this.shader);
|
|
||||||
this.camera.calculateViewMatrix(this.shader);
|
|
||||||
|
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(this.windowId)) {
|
|
||||||
|
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
|
|
||||||
|
|
||||||
double currentFrame = glfwGetTime();
|
|
||||||
|
|
||||||
|
|
||||||
this.deltaTime = currentFrame - this.lastFrame;
|
|
||||||
this.lastFrame = currentFrame;
|
|
||||||
|
|
||||||
this.camera.calculateViewMatrix(this.shader);
|
|
||||||
|
|
||||||
|
|
||||||
this.texture0.use(GL_TEXTURE0);
|
|
||||||
this.texture1.use(GL_TEXTURE1);
|
|
||||||
|
|
||||||
this.shader.use();
|
|
||||||
|
|
||||||
|
|
||||||
glBindVertexArray(vAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
|
|
||||||
|
|
||||||
for (int i = 0; i < this.cubePositions.length; i++) {
|
|
||||||
float angle = 50.0f * (i + 1) * (float) glfwGetTime();
|
|
||||||
Mat4 model = new Mat4().translate(this.cubePositions[i]).rotate(glm.INSTANCE.radians(angle), new Vec3(i / 0.5f + 0.1f, i / 0.3f + 0.1f, i / 0.1f + 0.1f));
|
|
||||||
this.shader.setMat4("model", model);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
glfwSwapBuffers(this.windowId); // swap the color buffers
|
|
||||||
|
|
||||||
// Poll for window events. The key callback above will only be
|
|
||||||
// invoked during this call.
|
|
||||||
glfwPollEvents();
|
|
||||||
handleInput();
|
|
||||||
this.camera.handleInput(this.deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
// Free the window callbacks and destroy the window
|
|
||||||
glfwFreeCallbacks(this.windowId);
|
|
||||||
glfwDestroyWindow(this.windowId);
|
|
||||||
|
|
||||||
// Terminate GLFW and free the error callback
|
|
||||||
glfwTerminate();
|
|
||||||
glfwSetErrorCallback(null).free();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void switchPolygonMode() {
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, (this.polygonEnabled ? GL_LINE : GL_FILL));
|
|
||||||
this.polygonEnabled = !this.polygonEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleInput() {
|
|
||||||
if (glfwGetKey(this.windowId, GLFW_KEY_UP) == GLFW_PRESS) {
|
|
||||||
this.shader.use();
|
|
||||||
this.visibilityLevel += 0.1f;
|
|
||||||
if (this.visibilityLevel > 1.0f) {
|
|
||||||
this.visibilityLevel = 1.0f;
|
|
||||||
}
|
|
||||||
this.shader.setFloat("visibility", this.visibilityLevel);
|
|
||||||
}
|
|
||||||
if (glfwGetKey(this.windowId, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
|
||||||
this.shader.use();
|
|
||||||
this.visibilityLevel -= 0.1f;
|
|
||||||
if (this.visibilityLevel < 0.0f) {
|
|
||||||
this.visibilityLevel = 0.0f;
|
|
||||||
}
|
|
||||||
this.shader.setFloat("visibility", this.visibilityLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
202
src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt
Normal file
202
src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
import org.lwjgl.*
|
||||||
|
import org.lwjgl.glfw.Callbacks
|
||||||
|
import org.lwjgl.glfw.GLFW.*
|
||||||
|
import org.lwjgl.glfw.GLFWErrorCallback
|
||||||
|
import org.lwjgl.glfw.GLFWWindowSizeCallback
|
||||||
|
import org.lwjgl.opengl.*
|
||||||
|
import org.lwjgl.opengl.GL11.glClear
|
||||||
|
import org.lwjgl.system.MemoryStack
|
||||||
|
import org.lwjgl.system.MemoryUtil
|
||||||
|
|
||||||
|
class RenderWindow {
|
||||||
|
private var screenWidth = 800
|
||||||
|
private var screenHeight = 600
|
||||||
|
private var polygonEnabled = false
|
||||||
|
private lateinit var shader: Shader
|
||||||
|
private lateinit var texture0: TextureArray
|
||||||
|
private var windowId: Long = 0
|
||||||
|
private var deltaTime = 0.0 // time between current frame and last frame
|
||||||
|
|
||||||
|
private var lastFrame = 0.0
|
||||||
|
private lateinit var camera: Camera
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
// Setup an error callback. The default implementation
|
||||||
|
// will print the error message in System.err.
|
||||||
|
GLFWErrorCallback.createPrint(System.err).set()
|
||||||
|
|
||||||
|
// Initialize Most GLFW functions will not work before doing this.
|
||||||
|
check(glfwInit()) { "Unable to initialize GLFW" }
|
||||||
|
|
||||||
|
// Configure GLFW
|
||||||
|
glfwDefaultWindowHints() // optional, the current window hints are already the default
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) // the window will stay hidden after creation
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE) // the window will be resizable
|
||||||
|
|
||||||
|
// Create the window
|
||||||
|
windowId = glfwCreateWindow(screenWidth, screenHeight, "Hello World!", MemoryUtil.NULL, MemoryUtil.NULL)
|
||||||
|
if (windowId == MemoryUtil.NULL) {
|
||||||
|
glfwTerminate()
|
||||||
|
throw RuntimeException("Failed to create the GLFW window")
|
||||||
|
}
|
||||||
|
camera = Camera(45f, windowId)
|
||||||
|
glfwSetWindowSizeCallback(windowId, object : GLFWWindowSizeCallback() {
|
||||||
|
override fun invoke(window: Long, width: Int, height: Int) {
|
||||||
|
GL11.glViewport(0, 0, width, height)
|
||||||
|
screenWidth = width
|
||||||
|
screenHeight = height
|
||||||
|
camera.calculateProjectionMatrix(screenWidth, screenHeight, shader)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
||||||
|
glfwSetKeyCallback(this.windowId) { windowId: Long, key: Int, scanCode: Int, action: Int, mods: Int ->
|
||||||
|
run {
|
||||||
|
if (action != GLFW_RELEASE) {
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
when (key) {
|
||||||
|
GLFW_KEY_ESCAPE -> {
|
||||||
|
glfwSetWindowShouldClose(this.windowId, true)
|
||||||
|
}
|
||||||
|
GLFW_KEY_P -> {
|
||||||
|
switchPolygonMode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED)
|
||||||
|
glfwSetCursorPosCallback(windowId) { windowId: Long, xPos: Double, yPos: Double -> camera.mouseCallback(xPos, yPos) }
|
||||||
|
MemoryStack.stackPush().let { stack ->
|
||||||
|
val pWidth = stack.mallocInt(1) // int*
|
||||||
|
val pHeight = stack.mallocInt(1) // int*
|
||||||
|
|
||||||
|
// Get the window size passed to glfwCreateWindow
|
||||||
|
glfwGetWindowSize(windowId, pWidth, pHeight)
|
||||||
|
|
||||||
|
// Get the resolution of the primary monitor
|
||||||
|
val videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor())
|
||||||
|
|
||||||
|
// Center the window
|
||||||
|
glfwSetWindowPos(windowId, (videoMode!!.width() - pWidth[0]) / 2, (videoMode.height() - pHeight[0]) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the OpenGL context current
|
||||||
|
glfwMakeContextCurrent(windowId)
|
||||||
|
// Enable v-sync
|
||||||
|
glfwSwapInterval(1)
|
||||||
|
|
||||||
|
|
||||||
|
// Make the window visible
|
||||||
|
glfwShowWindow(windowId)
|
||||||
|
GL.createCapabilities()
|
||||||
|
GL11.glClearColor(0.2f, 0.3f, 0.3f, 1.0f)
|
||||||
|
GL11.glEnable(GL11.GL_DEPTH_TEST)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startLoop() {
|
||||||
|
val chunk = DummyData.getDummyChunk()
|
||||||
|
|
||||||
|
texture0 = TextureArray(arrayOf("/textures/emerald_block.png", "/textures/brown_wool.png"))
|
||||||
|
texture0.load()
|
||||||
|
|
||||||
|
shader = Shader("vertex.glsl", "fragment.glsl")
|
||||||
|
shader.load()
|
||||||
|
shader.use()
|
||||||
|
shader.setInt("texture0", 0)
|
||||||
|
|
||||||
|
camera.calculateProjectionMatrix(screenWidth, screenHeight, shader)
|
||||||
|
camera.calculateViewMatrix(shader)
|
||||||
|
|
||||||
|
val preparedChunks = mutableListOf<Mesh>()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for ((sectionHeight, section) in chunk.sections) {
|
||||||
|
for ((location, block) in section.blocks) {
|
||||||
|
val textureIndex = when (block.fullIdentifier) {
|
||||||
|
"minecraft:dirt" -> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
preparedChunks.add(Mesh(textureIndex, Vec3(location.x, location.y + ProtocolDefinition.SECTION_HEIGHT_Y * sectionHeight, location.z)))
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var framesLastSecond = 0
|
||||||
|
var lastCalcTime = glfwGetTime()
|
||||||
|
while (!glfwWindowShouldClose(windowId)) {
|
||||||
|
glClear(GL11.GL_COLOR_BUFFER_BIT or GL11.GL_DEPTH_BUFFER_BIT) // clear the framebuffer
|
||||||
|
|
||||||
|
val currentFrame = glfwGetTime()
|
||||||
|
|
||||||
|
deltaTime = currentFrame - lastFrame
|
||||||
|
lastFrame = currentFrame
|
||||||
|
|
||||||
|
texture0.use(GL13.GL_TEXTURE0)
|
||||||
|
|
||||||
|
shader.use()
|
||||||
|
|
||||||
|
camera.calculateViewMatrix(shader)
|
||||||
|
|
||||||
|
for (mesh in preparedChunks) {
|
||||||
|
mesh.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
// for ((key, value) in chunk.sections) {
|
||||||
|
// for ((key1) in value.blocks) {
|
||||||
|
// val model = Mat4().translate(Vec3(key1.x, key1.y + ProtocolDefinition.SECTION_HEIGHT_Y * key, key1.z))
|
||||||
|
// shader.setMat4("model", model)
|
||||||
|
// glDrawArrays(GL11.GL_TRIANGLES, 0, 36)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
glfwSwapBuffers(windowId) // swap the color buffers
|
||||||
|
|
||||||
|
// Poll for window events. The key callback above will only be
|
||||||
|
// invoked during this call.
|
||||||
|
glfwPollEvents()
|
||||||
|
handleInput()
|
||||||
|
camera.handleInput(deltaTime)
|
||||||
|
if (glfwGetTime() - lastCalcTime >= 1.0) {
|
||||||
|
glfwSetWindowTitle(windowId, "FPS: $framesLastSecond")
|
||||||
|
lastCalcTime = glfwGetTime()
|
||||||
|
framesLastSecond = 0
|
||||||
|
}
|
||||||
|
framesLastSecond++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exit() {
|
||||||
|
// Free the window callbacks and destroy the window
|
||||||
|
Callbacks.glfwFreeCallbacks(windowId)
|
||||||
|
glfwDestroyWindow(windowId)
|
||||||
|
|
||||||
|
// Terminate GLFW and free the error callback
|
||||||
|
glfwTerminate()
|
||||||
|
glfwSetErrorCallback(null)!!.free()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun switchPolygonMode() {
|
||||||
|
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, if (polygonEnabled) {
|
||||||
|
GL11.GL_LINE
|
||||||
|
} else {
|
||||||
|
GL11.GL_FILL
|
||||||
|
})
|
||||||
|
polygonEnabled = !polygonEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleInput() {
|
||||||
|
}
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering;
|
|
||||||
|
|
||||||
import de.matthiasmann.twl.utils.PNGDecoder;
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL20.*;
|
|
||||||
import static org.lwjgl.opengl.GL30.glGenerateMipmap;
|
|
||||||
|
|
||||||
public class Texture {
|
|
||||||
private final String texturePath;
|
|
||||||
private int textureId;
|
|
||||||
|
|
||||||
public Texture(String texturePath) {
|
|
||||||
this.texturePath = texturePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int load() throws IOException {
|
|
||||||
this.textureId = glGenTextures();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, this.textureId);
|
|
||||||
// set the texture wrapping/filtering options (on the currently bound texture object)
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
// load and generate the texture
|
|
||||||
|
|
||||||
PNGDecoder decoder = new PNGDecoder(OpenGLUtil.class.getResourceAsStream(this.texturePath));
|
|
||||||
ByteBuffer buffer = BufferUtils.createByteBuffer(decoder.getWidth() * decoder.getHeight() * 4);
|
|
||||||
decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
|
|
||||||
buffer.flip();
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
|
||||||
return this.textureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTextureId() {
|
|
||||||
return this.textureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void use(int textureMode) {
|
|
||||||
glActiveTexture(textureMode); // activate the texture unit first before binding texture
|
|
||||||
glBindTexture(GL_TEXTURE_2D, this.textureId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,60 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering;
|
||||||
|
|
||||||
|
import de.matthiasmann.twl.utils.PNGDecoder;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL20.*;
|
||||||
|
import static org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY;
|
||||||
|
import static org.lwjgl.opengl.GL30.glGenerateMipmap;
|
||||||
|
|
||||||
|
public class TextureArray {
|
||||||
|
private final String[] texturePaths;
|
||||||
|
private int textureId;
|
||||||
|
|
||||||
|
public TextureArray(String[] texturePaths) {
|
||||||
|
this.texturePaths = texturePaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int load() throws IOException {
|
||||||
|
this.textureId = glGenTextures();
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, this.textureId);
|
||||||
|
// set the texture wrapping/filtering options (on the currently bound texture object)
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
// load and generate the texture
|
||||||
|
|
||||||
|
boolean sizeSet = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < this.texturePaths.length; i++) {
|
||||||
|
PNGDecoder decoder = new PNGDecoder(OpenGLUtil.class.getResourceAsStream(this.texturePaths[i]));
|
||||||
|
ByteBuffer buffer = BufferUtils.createByteBuffer(decoder.getWidth() * decoder.getHeight() * 4);
|
||||||
|
decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
|
||||||
|
buffer.flip();
|
||||||
|
if (!sizeSet) {
|
||||||
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), this.texturePaths.length, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null);
|
||||||
|
|
||||||
|
sizeSet = true;
|
||||||
|
}
|
||||||
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, decoder.getWidth(), decoder.getHeight(), 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
return this.textureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextureId() {
|
||||||
|
return this.textureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void use(int textureMode) {
|
||||||
|
glActiveTexture(textureMode); // activate the texture unit first before binding texture
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this.textureId);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,12 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
in vec3 vertexColor;
|
out vec4 outColor;
|
||||||
in vec2 TexCoord;
|
|
||||||
|
in vec3 passTextureCoordinates;
|
||||||
|
|
||||||
// texture sampler
|
// texture sampler
|
||||||
uniform sampler2D texture0;
|
uniform sampler2DArray texureArray;
|
||||||
uniform sampler2D texture1;
|
|
||||||
|
|
||||||
uniform float visibility;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 newTextCoord = vec2(TexCoord.x, -TexCoord.y);
|
outColor = texture(texureArray, passTextureCoordinates);
|
||||||
FragColor = mix(texture(texture0, newTextCoord), texture(texture1, newTextCoord), visibility);
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
layout (location = 0) in vec3 aPos;
|
layout (location = 0) in vec3 inPosition;
|
||||||
layout (location = 1) in vec2 aTexCoord;
|
layout (location = 1) in float textureIndex;
|
||||||
|
layout (location = 2) in float textureLayer;
|
||||||
|
|
||||||
out vec3 vertexColor;
|
out vec3 vertexColor;
|
||||||
out vec2 TexCoord;
|
out vec3 passTextureCoordinates;
|
||||||
|
|
||||||
|
|
||||||
uniform mat4 model;
|
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
vec2 textureIndexCoordinates[4] = vec2[4](
|
||||||
|
vec2(0.0f, 0.0f),
|
||||||
|
vec2(1.0f, 0.0f),
|
||||||
|
vec2(1.0f, 1.0f),
|
||||||
|
vec2(0.0f, 1.0f)
|
||||||
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
gl_Position = projection * view * vec4(inPosition, 1.0f);
|
||||||
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
|
passTextureCoordinates = vec3(textureIndexCoordinates[int(textureIndex)], textureLayer);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user