multi texture rendering, use vbos for rendering

This commit is contained in:
Bixilon 2021-02-03 16:34:34 +01:00
parent d06bba2eb6
commit 98beee726d
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
9 changed files with 425 additions and 369 deletions

View File

@ -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;
}
} }

View File

@ -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;
}
}

View 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);
}
}

View File

@ -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);
}
}
}

View 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() {
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
} }

View File

@ -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);
} }