Added ability to render mutiple players.

This commit is contained in:
Andrew Lalis 2022-07-17 16:24:41 +02:00
parent 6cf5b599d0
commit 833ca720f1
27 changed files with 1133 additions and 240 deletions

View File

@ -146,6 +146,11 @@
<artifactId>aos2-core</artifactId> <artifactId>aos2-core</artifactId>
<version>${parent.version}</version> <version>${parent.version}</version>
</dependency> </dependency>
<dependency>
<groupId>de.javagl</groupId>
<artifactId>obj</artifactId>
<version>0.3.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.lwjgl</groupId> <groupId>org.lwjgl</groupId>

View File

@ -5,16 +5,11 @@ import nl.andrewl.aos2_client.control.PlayerInputKeyCallback;
import nl.andrewl.aos2_client.control.PlayerInputMouseClickCallback; import nl.andrewl.aos2_client.control.PlayerInputMouseClickCallback;
import nl.andrewl.aos2_client.control.PlayerViewCursorCallback; import nl.andrewl.aos2_client.control.PlayerViewCursorCallback;
import nl.andrewl.aos2_client.render.GameRenderer; import nl.andrewl.aos2_client.render.GameRenderer;
import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.ColorPalette; import nl.andrewl.aos_core.model.ColorPalette;
import nl.andrewl.aos_core.model.World; import nl.andrewl.aos_core.net.*;
import nl.andrewl.aos_core.net.ChunkDataMessage;
import nl.andrewl.aos_core.net.ChunkHashMessage;
import nl.andrewl.aos_core.net.WorldInfoMessage;
import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage; import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage;
import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage; import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage;
import nl.andrewl.record_net.Message; import nl.andrewl.record_net.Message;
import org.joml.Vector3i;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -60,14 +55,18 @@ public class Client implements Runnable {
gameRenderer.setupWindow( gameRenderer.setupWindow(
new PlayerViewCursorCallback(gameRenderer.getCamera(), communicationHandler), new PlayerViewCursorCallback(gameRenderer.getCamera(), communicationHandler),
new PlayerInputKeyCallback(inputHandler), new PlayerInputKeyCallback(inputHandler),
new PlayerInputMouseClickCallback(inputHandler) new PlayerInputMouseClickCallback(inputHandler),
false,
false
); );
long lastFrameAt = System.currentTimeMillis(); long lastFrameAt = System.currentTimeMillis();
while (!gameRenderer.windowShouldClose()) { while (!gameRenderer.windowShouldClose()) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
float dt = (now - lastFrameAt) / 1000f; float dt = (now - lastFrameAt) / 1000f;
world.processQueuedChunkUpdates();
gameRenderer.getCamera().interpolatePosition(dt); gameRenderer.getCamera().interpolatePosition(dt);
world.interpolatePlayers(dt);
gameRenderer.draw(); gameRenderer.draw();
lastFrameAt = now; lastFrameAt = now;
} }
@ -75,31 +74,17 @@ public class Client implements Runnable {
communicationHandler.shutdown(); communicationHandler.shutdown();
} }
public int getClientId() {
return clientId;
}
public World getWorld() {
return world;
}
public void onMessageReceived(Message msg) { public void onMessageReceived(Message msg) {
if (msg instanceof WorldInfoMessage worldInfo) { if (msg instanceof WorldInfoMessage worldInfo) {
world.setPalette(ColorPalette.fromArray(worldInfo.palette())); world.setPalette(ColorPalette.fromArray(worldInfo.palette()));
} }
if (msg instanceof ChunkDataMessage chunkDataMessage) { if (msg instanceof ChunkDataMessage chunkDataMessage) {
Chunk chunk = chunkDataMessage.toChunk(); world.addChunk(chunkDataMessage);
world.addChunk(chunk);
gameRenderer.getChunkRenderer().queueChunkMesh(chunk);
} }
if (msg instanceof ChunkUpdateMessage u) { if (msg instanceof ChunkUpdateMessage u) {
Vector3i chunkPos = new Vector3i(u.cx(), u.cy(), u.cz()); world.updateChunk(u);
Chunk chunk = world.getChunkAt(chunkPos); // If we received an update for a chunk we don't have, request it!
System.out.println(u); if (world.getChunkAt(u.getChunkPos()) == null) {
if (chunk != null) {
chunk.setBlockAt(u.lx(), u.ly(), u.lz(), u.newBlock());
gameRenderer.getChunkRenderer().queueChunkMesh(chunk);
} else {
communicationHandler.sendMessage(new ChunkHashMessage(u.cx(), u.cy(), u.cz(), -1)); communicationHandler.sendMessage(new ChunkHashMessage(u.cx(), u.cy(), u.cz(), -1));
} }
} }
@ -108,9 +93,16 @@ public class Client implements Runnable {
float eyeHeight = playerUpdate.crouching() ? 1.3f : 1.7f; float eyeHeight = playerUpdate.crouching() ? 1.3f : 1.7f;
gameRenderer.getCamera().setPosition(playerUpdate.px(), playerUpdate.py() + eyeHeight, playerUpdate.pz()); gameRenderer.getCamera().setPosition(playerUpdate.px(), playerUpdate.py() + eyeHeight, playerUpdate.pz());
gameRenderer.getCamera().setVelocity(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz()); gameRenderer.getCamera().setVelocity(playerUpdate.vx(), playerUpdate.vy(), playerUpdate.vz());
// TODO: Unload far away chunks and request close chunks we don't have. } else {
world.playerUpdated(playerUpdate);
} }
} }
if (msg instanceof PlayerJoinMessage joinMessage) {
world.playerJoined(joinMessage);
}
if (msg instanceof PlayerLeaveMessage leaveMessage) {
world.playerLeft(leaveMessage);
}
} }

View File

@ -1,7 +1,138 @@
package nl.andrewl.aos2_client; package nl.andrewl.aos2_client;
import nl.andrewl.aos2_client.render.chunk.ChunkMesh;
import nl.andrewl.aos2_client.render.chunk.ChunkMeshGenerator;
import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.Player;
import nl.andrewl.aos_core.model.World; import nl.andrewl.aos_core.model.World;
import nl.andrewl.aos_core.net.ChunkDataMessage;
import nl.andrewl.aos_core.net.PlayerJoinMessage;
import nl.andrewl.aos_core.net.PlayerLeaveMessage;
import nl.andrewl.aos_core.net.udp.ChunkUpdateMessage;
import nl.andrewl.aos_core.net.udp.PlayerUpdateMessage;
import org.joml.Vector3f;
import org.joml.Vector3i;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* A client-side extension of the world model, with information that is only
* important for the client to know about, like other players and chunk render
* queues.
*/
public class ClientWorld extends World { public class ClientWorld extends World {
private final Queue<Chunk> chunkUpdateQueue = new ConcurrentLinkedQueue<>();
private final Queue<Chunk> chunkRemovalQueue = new ConcurrentLinkedQueue<>();
private final ChunkMeshGenerator chunkMeshGenerator = new ChunkMeshGenerator();
private final Map<Chunk, ChunkMesh> chunkMeshes = new ConcurrentHashMap<>();
private final Map<Integer, Player> players = new HashMap<>();
public void playerJoined(PlayerJoinMessage joinMessage) {
Player p = joinMessage.toPlayer();
players.put(p.getId(), p);
}
public void playerLeft(PlayerLeaveMessage leaveMessage) {
players.remove(leaveMessage.id());
}
public void playerUpdated(PlayerUpdateMessage playerUpdate) {
Player p = players.get(playerUpdate.clientId());
if (p != null) {
playerUpdate.apply(p);
}
}
public Collection<Player> getPlayers() {
return players.values();
}
public void interpolatePlayers(float dt) {
Vector3f movement = new Vector3f();
for (var player : getPlayers()) {
movement.set(player.getVelocity()).mul(dt);
player.getPosition().add(movement);
}
}
@Override
public void addChunk(Chunk chunk) {
super.addChunk(chunk);
chunkUpdateQueue.add(chunk);
}
public void addChunk(ChunkDataMessage msg) {
addChunk(msg.toChunk());
}
@Override
public void removeChunk(Vector3i chunkPos) {
Chunk chunk = getChunkAt(chunkPos);
if (chunk != null) {
chunkRemovalQueue.add(chunk);
chunkUpdateQueue.remove(chunk);
}
super.removeChunk(chunkPos);
}
public void updateChunk(ChunkUpdateMessage update) {
Chunk chunk = getChunkAt(update.getChunkPos());
if (chunk != null) {
chunk.setBlockAt(update.lx(), update.ly(), update.lz(), update.newBlock());
List<Chunk> chunksToReRender = new ArrayList<>(7);
chunksToReRender.add(chunk);
// Check if neighboring chunks need to be re-rendered too.
if (update.lx() == 0) {
Chunk c = getChunkAt(update.cx() - 1, update.cy(), update.cz());
if (c != null) chunksToReRender.add(c);
}
if (update.ly() == 0) {
Chunk c = getChunkAt(update.cx(), update.cy() - 1, update.cz());
if (c != null) chunksToReRender.add(c);
}
if (update.lz() == 0) {
Chunk c = getChunkAt(update.cx(), update.cy(), update.cz() - 1);
if (c != null) chunksToReRender.add(c);
}
if (update.lx() == Chunk.SIZE - 1) {
Chunk c = getChunkAt(update.cx() + 1, update.cy(), update.cz());
if (c != null) chunksToReRender.add(c);
}
if (update.ly() == Chunk.SIZE - 1) {
Chunk c = getChunkAt(update.cx(), update.cy() + 1, update.cz());
if (c != null) chunksToReRender.add(c);
}
if (update.lz() == Chunk.SIZE - 1) {
Chunk c = getChunkAt(update.cx(), update.cy(), update.cz() + 1);
if (c != null) chunksToReRender.add(c);
}
chunkUpdateQueue.addAll(chunksToReRender);
}
}
/**
* Call this to process any queued chunk updates, and update chunk meshes.
* Only call this method on the main OpenGL context thread!
*/
public void processQueuedChunkUpdates() {
while (!chunkRemovalQueue.isEmpty()) {
Chunk chunk = chunkRemovalQueue.remove();
ChunkMesh mesh = chunkMeshes.remove(chunk);
if (mesh != null) mesh.free();
}
while (!chunkUpdateQueue.isEmpty()) {
Chunk chunk = chunkUpdateQueue.remove();
ChunkMesh mesh = new ChunkMesh(chunk, this, chunkMeshGenerator);
ChunkMesh existingMesh = chunkMeshes.get(chunk);
if (existingMesh != null) existingMesh.free();
chunkMeshes.put(chunk, mesh);
}
}
public Collection<ChunkMesh> getChunkMeshesToDraw() {
return chunkMeshes.values();
}
} }

View File

@ -14,7 +14,6 @@ public class PlayerInputMouseClickCallback implements GLFWMouseButtonCallbackI {
@Override @Override
public void invoke(long window, int button, int action, int mods) { public void invoke(long window, int button, int action, int mods) {
System.out.println("Click: " + button);
inputHandler.updateInputState(window); inputHandler.updateInputState(window);
} }
} }

View File

@ -1,10 +1,11 @@
package nl.andrewl.aos2_client.render; package nl.andrewl.aos2_client.render;
import nl.andrewl.aos2_client.Camera; import nl.andrewl.aos2_client.Camera;
import nl.andrewl.aos2_client.ClientWorld;
import nl.andrewl.aos2_client.render.chunk.ChunkRenderer; import nl.andrewl.aos2_client.render.chunk.ChunkRenderer;
import nl.andrewl.aos2_client.render.gui.GUIRenderer; import nl.andrewl.aos2_client.render.gui.GUIRenderer;
import nl.andrewl.aos2_client.render.gui.GUITexture; import nl.andrewl.aos2_client.render.gui.GUITexture;
import nl.andrewl.aos_core.model.World; import nl.andrewl.aos2_client.render.model.Model;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.lwjgl.glfw.*; import org.lwjgl.glfw.*;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
@ -27,30 +28,33 @@ public class GameRenderer {
private static final float Z_NEAR = 0.01f; private static final float Z_NEAR = 0.01f;
private static final float Z_FAR = 500f; private static final float Z_FAR = 500f;
private final ChunkRenderer chunkRenderer; private ChunkRenderer chunkRenderer;
private final GUIRenderer guiRenderer; private GUIRenderer guiRenderer;
private ModelRenderer modelRenderer;
private final Camera camera; private final Camera camera;
private final World world; private final ClientWorld world;
private Model playerModel; // Standard player model used to render all players.
private long windowHandle; private long windowHandle;
private GLFWVidMode primaryMonitorSettings;
private boolean fullscreen;
private int screenWidth = 800; private int screenWidth = 800;
private int screenHeight = 600; private int screenHeight = 600;
private float fov = 90f; private float fov = 90f;
private final Matrix4f perspectiveTransform; private final Matrix4f perspectiveTransform;
public GameRenderer(World world) { public GameRenderer(ClientWorld world) {
this.world = world; this.world = world;
this.chunkRenderer = new ChunkRenderer();
this.guiRenderer = new GUIRenderer();
this.camera = new Camera(); this.camera = new Camera();
this.perspectiveTransform = new Matrix4f(); this.perspectiveTransform = new Matrix4f();
} }
public void setupWindow(GLFWCursorPosCallbackI viewCursorCallback, GLFWKeyCallbackI inputKeyCallback, GLFWMouseButtonCallbackI mouseButtonCallback) { public void setupWindow(
GLFWCursorPosCallbackI viewCursorCallback,
GLFWKeyCallbackI inputKeyCallback,
GLFWMouseButtonCallbackI mouseButtonCallback,
boolean fullscreen,
boolean grabCursor
) {
GLFWErrorCallback.createPrint(System.err).set(); GLFWErrorCallback.createPrint(System.err).set();
if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW."); if (!glfwInit()) throw new IllegalStateException("Could not initialize GLFW.");
glfwDefaultWindowHints(); glfwDefaultWindowHints();
@ -58,21 +62,28 @@ public class GameRenderer {
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
long monitorId = glfwGetPrimaryMonitor(); long monitorId = glfwGetPrimaryMonitor();
primaryMonitorSettings = glfwGetVideoMode(monitorId); GLFWVidMode primaryMonitorSettings = glfwGetVideoMode(monitorId);
if (primaryMonitorSettings == null) throw new IllegalStateException("Could not get information about the primary monitory."); if (primaryMonitorSettings == null) throw new IllegalStateException("Could not get information about the primary monitory.");
log.debug("Primary monitor settings: Width: {}, Height: {}", primaryMonitorSettings.width(), primaryMonitorSettings.height()); log.debug("Primary monitor settings: Width: {}, Height: {}", primaryMonitorSettings.width(), primaryMonitorSettings.height());
screenWidth = primaryMonitorSettings.width(); if (fullscreen) {
screenHeight = primaryMonitorSettings.height(); screenWidth = primaryMonitorSettings.width();
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", monitorId, 0); screenHeight = primaryMonitorSettings.height();
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", monitorId, 0);
} else {
screenWidth = 1000;
screenHeight = 800;
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", 0, 0);
}
if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window."); if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window.");
fullscreen = true;
log.debug("Initialized GLFW window."); log.debug("Initialized GLFW window.");
// Setup callbacks. // Setup callbacks.
glfwSetKeyCallback(windowHandle, inputKeyCallback); glfwSetKeyCallback(windowHandle, inputKeyCallback);
glfwSetCursorPosCallback(windowHandle, viewCursorCallback); glfwSetCursorPosCallback(windowHandle, viewCursorCallback);
glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback); glfwSetMouseButtonCallback(windowHandle, mouseButtonCallback);
glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); if (grabCursor) {
glfwSetInputMode(windowHandle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
glfwSetInputMode(windowHandle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); glfwSetInputMode(windowHandle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
glfwSetCursorPos(windowHandle, 0, 0); glfwSetCursorPos(windowHandle, 0, 0);
log.debug("Set up window callbacks."); log.debug("Set up window callbacks.");
@ -80,7 +91,6 @@ public class GameRenderer {
glfwMakeContextCurrent(windowHandle); glfwMakeContextCurrent(windowHandle);
glfwSwapInterval(1); glfwSwapInterval(1);
glfwShowWindow(windowHandle); glfwShowWindow(windowHandle);
log.debug("Made window visible.");
GL.createCapabilities(); GL.createCapabilities();
// GLUtil.setupDebugMessageCallback(System.out); // GLUtil.setupDebugMessageCallback(System.out);
@ -90,9 +100,9 @@ public class GameRenderer {
glCullFace(GL_BACK); glCullFace(GL_BACK);
log.debug("Initialized OpenGL context."); log.debug("Initialized OpenGL context.");
chunkRenderer.setupShaderProgram(); this.chunkRenderer = new ChunkRenderer();
log.debug("Initialized chunk renderer."); log.debug("Initialized chunk renderer.");
guiRenderer.setup(); this.guiRenderer = new GUIRenderer();
// TODO: More organized way to load textures for GUI. // TODO: More organized way to load textures for GUI.
try { try {
var crosshairTexture = new GUITexture("gui/crosshair.png"); var crosshairTexture = new GUITexture("gui/crosshair.png");
@ -103,34 +113,13 @@ public class GameRenderer {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
log.debug("Initialized GUI renderer."); log.debug("Initialized GUI renderer.");
updatePerspective(); this.modelRenderer = new ModelRenderer();
} try {
playerModel = new Model("model/player_simple.obj", "model/simple_player.png");
public void setFullscreen(boolean fullscreen) { } catch (IOException e) {
if (windowHandle == 0) throw new IllegalStateException("Window not setup."); throw new RuntimeException(e);
long monitor = glfwGetPrimaryMonitor();
if (fullscreen) {
log.debug("Changing to fullscreen: {} x {}", primaryMonitorSettings.width(), primaryMonitorSettings.height());
glfwSetWindowMonitor(windowHandle, monitor, 0, 0, primaryMonitorSettings.width(), primaryMonitorSettings.height(), primaryMonitorSettings.refreshRate());
screenWidth = primaryMonitorSettings.width();
screenHeight = primaryMonitorSettings.height();
updatePerspective();
} else {
log.debug("Changing to windowed mode.");
screenWidth = 800;
screenHeight = 600;
int left = primaryMonitorSettings.width() / 2;
int top = primaryMonitorSettings.height() / 2;
glfwSetWindowMonitor(windowHandle, 0, left, top, screenWidth, screenHeight, primaryMonitorSettings.refreshRate());
updatePerspective();
} }
this.fullscreen = fullscreen; log.debug("Initialized model renderer.");
}
public void setSize(int width, int height) {
glfwSetWindowSize(windowHandle, width, height);
this.screenWidth = width;
this.screenHeight = height;
updatePerspective(); updatePerspective();
} }
@ -144,12 +133,18 @@ public class GameRenderer {
} }
/** /**
* Updates the rendering perspective used to render the game. Note: only * Updates the rendering perspective used to render the game.
* call this after calling {@link ChunkRenderer#setupShaderProgram()}.
*/ */
private void updatePerspective() { private void updatePerspective() {
perspectiveTransform.setPerspective(fov, getAspectRatio(), Z_NEAR, Z_FAR); perspectiveTransform.setPerspective(fov, getAspectRatio(), Z_NEAR, Z_FAR);
chunkRenderer.setPerspective(perspectiveTransform); float[] data = new float[16];
perspectiveTransform.get(data);
if (chunkRenderer != null) chunkRenderer.setPerspective(data);
if (modelRenderer != null) modelRenderer.setPerspective(data);
}
public Matrix4f getPerspectiveTransform() {
return perspectiveTransform;
} }
public boolean windowShouldClose() { public boolean windowShouldClose() {
@ -160,14 +155,20 @@ public class GameRenderer {
return camera; return camera;
} }
public ChunkRenderer getChunkRenderer() {
return chunkRenderer;
}
public void draw() { public void draw() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
chunkRenderer.draw(camera, world.getChunkMeshesToDraw());
// Draw players.
modelRenderer.setView(camera.getViewTransformData());
playerModel.bind();
Matrix4f playerModelTransform = new Matrix4f();
for (var player : world.getPlayers()) {
playerModelTransform.identity().translate(player.getPosition());
modelRenderer.render(playerModel, playerModelTransform);
}
playerModel.unbind();
chunkRenderer.draw(camera, world);
guiRenderer.draw(); guiRenderer.draw();
glfwSwapBuffers(windowHandle); glfwSwapBuffers(windowHandle);
@ -175,8 +176,10 @@ public class GameRenderer {
} }
public void freeWindow() { public void freeWindow() {
guiRenderer.free(); if (playerModel != null) playerModel.free();
chunkRenderer.free(); if (modelRenderer != null) modelRenderer.free();
if (guiRenderer != null) guiRenderer.free();
if (chunkRenderer != null) chunkRenderer.free();
GL.destroy(); GL.destroy();
Callbacks.glfwFreeCallbacks(windowHandle); Callbacks.glfwFreeCallbacks(windowHandle);
glfwSetErrorCallback(null); glfwSetErrorCallback(null);

View File

@ -1,70 +0,0 @@
package nl.andrewl.aos2_client.render;
import org.joml.Matrix4f;
import static org.lwjgl.opengl.GL46.*;
public class Mesh {
private final int vboId;
private final int vaoId;
private final int eboId;
private int indexCount;
private final Matrix4f transform = new Matrix4f();
private final float[] transformData = new float[16];
public Mesh(MeshData initialData) {
this.vboId = glGenBuffers();
this.eboId = glGenBuffers();
this.vaoId = glGenVertexArrays();
load(initialData);
initVertexArrayAttributes();
}
public void load(MeshData data) {
indexCount = data.indexBuffer().limit();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, data.vertexBuffer(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indexBuffer(), GL_STATIC_DRAW);
}
public Matrix4f getTransform() {
return transform;
}
public void updateTransform() {
transform.set(transformData);
}
public float[] getTransformData() {
return transformData;
}
/**
* Initializes this mesh's vertex array attribute settings.
*/
private void initVertexArrayAttributes() {
glBindVertexArray(vaoId);
// Vertex position floats.
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 9 * Float.BYTES, 0);
// Vertex color floats.
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 9 * Float.BYTES, 3 * Float.BYTES);
// Vertex normal floats.
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, false, 9 * Float.BYTES, 6 * Float.BYTES);
}
public void draw() {
glBindVertexArray(vaoId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
}
public void free() {
glDeleteBuffers(vboId);
glDeleteBuffers(eboId);
glDeleteVertexArrays(vaoId);
}
}

View File

@ -1,6 +0,0 @@
package nl.andrewl.aos2_client.render;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public record MeshData(FloatBuffer vertexBuffer, IntBuffer indexBuffer) {}

View File

@ -0,0 +1,53 @@
package nl.andrewl.aos2_client.render;
import nl.andrewl.aos2_client.Camera;
import nl.andrewl.aos2_client.render.model.Model;
import org.joml.Matrix4f;
import static org.lwjgl.opengl.GL46.*;
/**
* A renderer that handles rendering of textured models.
*/
public class ModelRenderer {
private final ShaderProgram shaderProgram;
private final int projectionUniform;
private final int viewUniform;
private final int modelUniform;
private final int textureSamplerUniform;
public ModelRenderer() {
shaderProgram = new ShaderProgram.Builder()
.withShader("shader/model/vertex.glsl", GL_VERTEX_SHADER)
.withShader("shader/model/fragment.glsl", GL_FRAGMENT_SHADER)
.build();
projectionUniform = shaderProgram.getUniform("projectionTransform");
viewUniform = shaderProgram.getUniform("viewTransform");
modelUniform = shaderProgram.getUniform("modelTransform");
textureSamplerUniform = shaderProgram.getUniform("textureSampler");
}
public void setPerspective(float[] data) {
shaderProgram.use();
glUniformMatrix4fv(projectionUniform, false, data);
shaderProgram.stopUsing();
}
public void setView(float[] data) {
shaderProgram.use();
glUniformMatrix4fv(viewUniform, false, data);
shaderProgram.stopUsing();
}
public void render(Model model, Matrix4f modelTransform) {
shaderProgram.use();
glUniformMatrix4fv(modelUniform, false, modelTransform.get(new float[16]));
glUniform1i(textureSamplerUniform, 0);
model.draw();
shaderProgram.stopUsing();
}
public void free() {
shaderProgram.free();
}
}

View File

@ -1,26 +0,0 @@
package nl.andrewl.aos2_client.render;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class PlayerMeshGenerator {
private final FloatBuffer vertexBuffer;
private final IntBuffer indexBuffer;
private final Vector3i pos = new Vector3i();
private final Vector3f color = new Vector3f();
private final Vector3f norm = new Vector3f();
public PlayerMeshGenerator() {
vertexBuffer = BufferUtils.createFloatBuffer(1000);
indexBuffer = BufferUtils.createIntBuffer(100);
}
// public PlayerMesh generateMesh() {
//
// }
}

View File

@ -32,6 +32,10 @@ public class ShaderProgram {
glUseProgram(0); glUseProgram(0);
} }
public int getId() {
return id;
}
public int getUniform(String name) { public int getUniform(String name) {
return glGetUniformLocation(id, name); return glGetUniformLocation(id, name);
} }

View File

@ -49,17 +49,16 @@ public class ChunkMesh {
* Generates and loads this chunk's mesh into the allocated OpenGL buffers. * Generates and loads this chunk's mesh into the allocated OpenGL buffers.
*/ */
private void loadMesh(ChunkMeshGenerator meshGenerator) { private void loadMesh(ChunkMeshGenerator meshGenerator) {
long start = System.nanoTime(); // long start = System.nanoTime();
var meshData = meshGenerator.generateMesh(chunk, world); var meshData = meshGenerator.generateMesh(chunk, world);
double dur = (System.nanoTime() - start) / 1_000_000.0; // double dur = (System.nanoTime() - start) / 1_000_000.0;
this.indexCount = meshData.indexBuffer().limit(); this.indexCount = meshData.indexBuffer().limit();
// Print some debug information. // log.debug(
log.debug( // "Generated mesh for chunk ({}, {}, {}) in {} ms. {} vertices and {} indices.",
"Generated mesh for chunk ({}, {}, {}) in {} ms. {} vertices and {} indices.", // chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z,
chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z, // dur,
dur, // meshData.vertexBuffer().limit() / 9, indexCount
meshData.vertexBuffer().limit() / 9, indexCount // );
);
glBindBuffer(GL_ARRAY_BUFFER, vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, meshData.vertexBuffer(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, meshData.vertexBuffer(), GL_STATIC_DRAW);

View File

@ -7,7 +7,10 @@ import nl.andrewl.aos_core.model.World;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Vector3i; import org.joml.Vector3i;
import java.util.*; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import static org.lwjgl.opengl.GL46.*; import static org.lwjgl.opengl.GL46.*;
@ -18,17 +21,12 @@ import static org.lwjgl.opengl.GL46.*;
* be rendered each frame. * be rendered each frame.
*/ */
public class ChunkRenderer { public class ChunkRenderer {
private final ChunkMeshGenerator chunkMeshGenerator = new ChunkMeshGenerator(); private final ShaderProgram shaderProgram;
private final Queue<Chunk> meshGenerationQueue = new ConcurrentLinkedQueue<>(); private final int projectionTransformUniform;
private final int viewTransformUniform;
private final int chunkPositionUniform;
private ShaderProgram shaderProgram; public ChunkRenderer() {
private int projectionTransformUniform;
private int viewTransformUniform;
private int chunkPositionUniform;
private final Map<Vector3i, ChunkMesh> chunkMeshes = new HashMap<>();
public void setupShaderProgram() {
this.shaderProgram = new ShaderProgram.Builder() this.shaderProgram = new ShaderProgram.Builder()
.withShader("shader/chunk/vertex.glsl", GL_VERTEX_SHADER) .withShader("shader/chunk/vertex.glsl", GL_VERTEX_SHADER)
.withShader("shader/chunk/fragment.glsl", GL_FRAGMENT_SHADER) .withShader("shader/chunk/fragment.glsl", GL_FRAGMENT_SHADER)
@ -38,39 +36,28 @@ public class ChunkRenderer {
this.viewTransformUniform = shaderProgram.getUniform("viewTransform"); this.viewTransformUniform = shaderProgram.getUniform("viewTransform");
this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition"); this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition");
int chunkSizeUniform = shaderProgram.getUniform("chunkSize"); int chunkSizeUniform = shaderProgram.getUniform("chunkSize");
// Set constant uniforms that don't change during runtime. // Set constant uniforms that don't change during runtime.
glUniform1i(chunkSizeUniform, Chunk.SIZE); glUniform1i(chunkSizeUniform, Chunk.SIZE);
shaderProgram.stopUsing();
} }
public void queueChunkMesh(Chunk chunk) { public void setPerspective(float[] data) {
meshGenerationQueue.add(chunk); shaderProgram.use();
glUniformMatrix4fv(projectionTransformUniform, false, data);
shaderProgram.stopUsing();
} }
public void setPerspective(Matrix4f projectionTransform) { public void draw(Camera cam, Collection<ChunkMesh> chunkMeshes) {
glUniformMatrix4fv(projectionTransformUniform, false, projectionTransform.get(new float[16]));
}
public void draw(Camera cam, World world) {
while (!meshGenerationQueue.isEmpty()) {
Chunk chunk = meshGenerationQueue.remove();
ChunkMesh mesh = new ChunkMesh(chunk, world, chunkMeshGenerator);
ChunkMesh existingMesh = chunkMeshes.get(chunk.getPosition());
if (existingMesh != null) existingMesh.free();
chunkMeshes.put(chunk.getPosition(), mesh);
}
shaderProgram.use(); shaderProgram.use();
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData()); glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
for (var mesh : chunkMeshes.values()) { for (var mesh : chunkMeshes) {
glUniform3iv(chunkPositionUniform, mesh.getPositionData()); glUniform3iv(chunkPositionUniform, mesh.getPositionData());
mesh.draw(); mesh.draw();
} }
shaderProgram.stopUsing();
} }
public void free() { public void free() {
for (var mesh : chunkMeshes.values()) mesh.free();
chunkMeshes.clear();
meshGenerationQueue.clear();
shaderProgram.free(); shaderProgram.free();
} }
} }

View File

@ -14,20 +14,16 @@ import static org.lwjgl.opengl.GL46.*;
* Manages rendering of 2D GUI components like cross-hairs, inventory stuff, etc. * Manages rendering of 2D GUI components like cross-hairs, inventory stuff, etc.
*/ */
public class GUIRenderer { public class GUIRenderer {
private int vaoId; private final int vaoId;
private int vboId; private final int vboId;
private int vertexCount; private final int vertexCount;
private ShaderProgram shaderProgram; private final ShaderProgram shaderProgram;
private int transformUniformLocation; private final int transformUniformLocation;
private final List<GUITexture> guiTextures = new ArrayList<>(); private final List<GUITexture> guiTextures = new ArrayList<>();
public void addTexture(GUITexture texture) { public GUIRenderer() {
guiTextures.add(texture);
}
public void setup() {
vaoId = glGenVertexArrays(); vaoId = glGenVertexArrays();
vboId = glGenBuffers(); vboId = glGenBuffers();
FloatBuffer buffer = BufferUtils.createFloatBuffer(8); FloatBuffer buffer = BufferUtils.createFloatBuffer(8);
@ -53,6 +49,10 @@ public class GUIRenderer {
shaderProgram.bindAttribute(0, "position"); shaderProgram.bindAttribute(0, "position");
} }
public void addTexture(GUITexture texture) {
guiTextures.add(texture);
}
public void draw() { public void draw() {
shaderProgram.use(); shaderProgram.use();
glBindVertexArray(vaoId); glBindVertexArray(vaoId);

View File

@ -26,7 +26,7 @@ public class GUITexture {
textureId = glGenTextures(); textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId); glBindTexture(GL_TEXTURE_2D, textureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, textureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
var buf = ImageUtils.decodePng(img); var buf = ImageUtils.decodePng(img);

View File

@ -0,0 +1,123 @@
package nl.andrewl.aos2_client.render.model;
import de.javagl.obj.Obj;
import de.javagl.obj.ObjData;
import de.javagl.obj.ObjReader;
import de.javagl.obj.ObjUtils;
import nl.andrewl.aos_core.ImageUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL46.*;
/**
* Represents a 3D model with a texture, which can be used to render one or
* more entities.
*/
public class Model {
private final int vaoId;
private final List<Integer> vboIds;
private final int eboId;
private final int indexCount;
private final int textureId;
public Model(String resource, String textureResource) throws IOException {
try (
var in = Model.class.getClassLoader().getResourceAsStream(resource);
var imageIn = Model.class.getClassLoader().getResourceAsStream(textureResource)
) {
if (in == null) throw new IOException("Could not load resource: " + resource);
if (imageIn == null) throw new IOException("Could not load texture image: " + textureResource);
Obj obj = ObjReader.read(in);
obj = ObjUtils.convertToRenderable(obj);
IntBuffer indices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
FloatBuffer texCoords = ObjData.getTexCoords(obj, 2, true);
FloatBuffer normals = ObjData.getNormals(obj);
indexCount = indices.limit();
vboIds = new ArrayList<>(4);
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Position data
int vboId = glGenBuffers();
vboIds.add(vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Normal data
vboId = glGenBuffers();
vboIds.add(vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, normals, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
// Texture data
vboId = glGenBuffers();
vboIds.add(vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(2); // Texture coordinates
glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0);
// Index data
eboId = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
BufferedImage img = ImageIO.read(imageIn);
int w = img.getWidth();
int h = img.getHeight();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ByteBuffer imageBuffer = ImageUtils.decodePng(img);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer);
}
}
public void bind() {
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
}
public void draw() {
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
}
public void unbind() {
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindTexture(GL_TEXTURE_2D, 0);
}
public void free() {
glDeleteTextures(textureId);
glDeleteBuffers(eboId);
for (var vboId : vboIds) {
glDeleteBuffers(vboId);
}
glDeleteVertexArrays(vaoId);
}
}

View File

@ -0,0 +1,13 @@
# Blender MTL File: 'player_simple.blend'
# Material Count: 1
newmtl Material.001
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd simple_player.png

View File

@ -0,0 +1,604 @@
# Blender v2.82 (sub 7) OBJ File: 'player_simple.blend'
# www.blender.org
mtllib player_simple.mtl
o Cube
v 0.307055 1.384430 -0.307055
v 0.159554 0.004036 -0.159554
v 0.307055 1.384430 0.307055
v 0.159554 0.004036 0.159554
v -0.307055 1.384430 -0.307055
v -0.159554 0.004036 -0.159554
v -0.307055 1.384430 0.307055
v -0.159554 0.004036 0.159554
v 0.000000 0.004036 -0.221565
v 0.000000 1.384430 0.426394
v 0.000000 0.004036 0.221565
v 0.000000 1.384430 -0.426394
v -0.221565 0.004036 0.000000
v 0.426394 1.384430 0.000000
v -0.426394 1.384430 0.000000
v 0.221565 0.004036 0.000000
v 0.000000 0.004036 0.000000
v 0.125637 1.521320 -0.125637
v 0.355691 0.694233 -0.355691
v -0.355691 0.694233 0.355691
v 0.355691 0.694233 0.355691
v -0.355691 0.694233 -0.355691
v 0.000000 0.694233 -0.493931
v 0.000000 0.694233 0.493931
v 0.493931 0.694233 -0.000000
v -0.493931 0.694233 -0.000000
v 0.342552 0.349135 -0.342552
v 0.342552 0.349135 0.342552
v -0.342552 0.349135 -0.342552
v 0.000000 0.349135 -0.475686
v 0.000000 0.349135 0.475686
v 0.475686 0.349135 -0.000000
v -0.475686 0.349135 -0.000000
v -0.342552 0.349135 0.342552
v -0.342552 1.039332 0.342552
v 0.342552 1.039332 -0.342552
v 0.342552 1.039332 0.342552
v -0.342552 1.039332 -0.342552
v 0.000000 1.039332 -0.475686
v 0.000000 1.039332 0.475686
v 0.475686 1.039332 -0.000000
v -0.475686 1.039332 -0.000000
v 0.324796 0.176514 -0.324796
v 0.324796 0.176514 0.324796
v -0.324796 0.176514 -0.324796
v 0.000000 0.176514 -0.451029
v 0.000000 0.176514 0.451029
v 0.451029 0.176514 -0.000000
v -0.451029 0.176514 -0.000000
v -0.324796 0.176514 0.324796
v 0.274970 0.090275 -0.274970
v 0.274970 0.090275 0.274970
v -0.274970 0.090275 -0.274970
v 0.000000 0.090275 -0.381838
v 0.000000 0.090275 0.381838
v 0.381838 0.090275 -0.000000
v -0.381838 0.090275 -0.000000
v -0.274970 0.090275 0.274970
v 0.230376 1.470570 -0.230376
v 0.230376 1.470570 0.230376
v -0.230376 1.470570 -0.230376
v -0.230376 1.470570 0.230376
v 0.000000 1.470570 0.319913
v 0.000000 1.470570 -0.319913
v 0.319913 1.470570 0.000000
v -0.319913 1.470570 0.000000
v 0.125637 1.556870 -0.125637
v 0.125637 1.521320 0.125637
v -0.125637 1.521320 -0.125637
v -0.125637 1.521320 0.125637
v 0.000000 1.521320 0.174467
v 0.000000 1.521320 -0.174467
v 0.174467 1.521320 0.000000
v -0.174467 1.521320 0.000000
v 0.169463 1.610223 -0.169463
v 0.125637 1.556870 0.125637
v -0.125637 1.556870 -0.125637
v -0.125637 1.556870 0.125637
v 0.000000 1.556870 0.174467
v 0.000000 1.556870 -0.174467
v 0.174467 1.556870 0.000000
v -0.174467 1.556870 0.000000
v 0.210794 1.686314 -0.210794
v 0.169463 1.610223 0.169463
v -0.169463 1.610223 -0.169463
v -0.169463 1.610223 0.169463
v 0.000000 1.610223 0.235325
v 0.000000 1.610223 -0.235325
v 0.235325 1.610223 0.000000
v -0.235325 1.610223 0.000000
v 0.223284 1.833569 -0.223284
v 0.210794 1.686314 0.210794
v -0.210794 1.686314 -0.210794
v -0.210794 1.686314 0.210794
v 0.000000 1.686314 0.292720
v 0.000000 1.686314 -0.292720
v 0.292720 1.686314 0.000000
v -0.292720 1.686314 0.000000
v 0.211578 1.977176 -0.211578
v 0.223284 1.833569 0.223284
v -0.223284 1.833569 -0.223284
v -0.223284 1.833569 0.223284
v 0.000000 1.833569 0.310064
v 0.000000 1.833569 -0.310064
v 0.310064 1.833569 0.000000
v -0.310064 1.833569 0.000000
v 0.172806 2.077383 -0.172806
v 0.211578 1.977176 0.211578
v -0.211578 1.977176 -0.211578
v -0.211578 1.977176 0.211578
v 0.000000 1.977176 0.293809
v 0.000000 1.977176 -0.293809
v 0.293809 1.977176 0.000000
v -0.293809 1.977176 0.000000
v 0.067534 2.131719 -0.067534
v 0.172806 2.077383 0.172806
v -0.172806 2.077383 -0.172806
v -0.172806 2.077383 0.172806
v 0.000000 2.077383 0.239968
v 0.000000 2.077383 -0.239968
v 0.239968 2.077383 0.000000
v -0.239968 2.077383 0.000000
v 0.067534 2.131719 0.067534
v -0.067534 2.131719 -0.067534
v -0.067534 2.131719 0.067534
v 0.000000 2.131719 0.093781
v 0.000000 2.131719 -0.093781
v 0.093781 2.131719 0.000000
v -0.093781 2.131719 0.000000
v 0.000000 2.131719 0.000000
vt 0.270204 0.781152
vt 0.118734 0.781152
vt 0.138824 0.736777
vt 0.252468 0.736777
vt 0.757867 0.465320
vt 0.690242 0.473338
vt 0.690321 0.364703
vt 0.757955 0.344126
vt 0.757867 0.142172
vt 0.690242 0.150190
vt 0.690321 0.041556
vt 0.757955 0.020979
vt 0.210691 0.204882
vt 0.247595 0.112545
vt 0.305645 0.164231
vt 0.305645 0.240769
vt 0.499666 0.142172
vt 0.432041 0.150190
vt 0.432120 0.041555
vt 0.499754 0.020979
vt 0.499666 0.465320
vt 0.432041 0.473338
vt 0.432120 0.364703
vt 0.499754 0.344126
vt 0.499754 0.629641
vt 0.432120 0.620631
vt 0.173786 0.297218
vt 0.252494 0.297218
vt 0.757955 0.629641
vt 0.690321 0.620631
vt 0.016446 0.672518
vt 0.016446 0.525224
vt 0.062080 0.544760
vt 0.062080 0.655271
vt 0.381919 0.534391
vt 0.381919 0.681685
vt 0.336285 0.662149
vt 0.336285 0.551638
vt 0.115736 0.245532
vt 0.115736 0.168995
vt 0.499754 0.306493
vt 0.432120 0.297484
vt 0.168888 0.112545
vt 0.757955 0.306493
vt 0.690321 0.297484
vt 0.893270 0.306425
vt 0.825604 0.309807
vt 0.825512 0.139183
vt 0.893182 0.142104
vt 0.635069 0.306425
vt 0.567403 0.309807
vt 0.567311 0.139183
vt 0.634981 0.142104
vt 0.893270 0.629572
vt 0.825604 0.632954
vt 0.825512 0.462330
vt 0.893182 0.465251
vt 0.635069 0.629572
vt 0.567403 0.632954
vt 0.567311 0.462330
vt 0.634981 0.465251
vt 0.567403 0.336488
vt 0.635069 0.344058
vt 0.567403 0.013341
vt 0.635069 0.020910
vt 0.825604 0.013341
vt 0.893270 0.020910
vt 0.825604 0.336488
vt 0.893270 0.344058
vt 0.927041 0.469228
vt 0.927124 0.354316
vt 0.927041 0.146080
vt 0.927124 0.031169
vt 0.668840 0.146080
vt 0.668923 0.031169
vt 0.668840 0.469228
vt 0.668923 0.354316
vt 0.668923 0.625032
vt 0.927124 0.625032
vt 0.668923 0.301884
vt 0.927124 0.301884
vt 0.282733 0.364011
vt 0.295787 0.392847
vt 0.135566 0.392847
vt 0.147091 0.364011
vt 0.138649 0.045752
vt 0.125594 0.016917
vt 0.285815 0.016917
vt 0.274291 0.045752
vt 0.374332 0.134826
vt 0.403985 0.122132
vt 0.403985 0.277935
vt 0.374332 0.266728
vt 0.047049 0.274937
vt 0.017396 0.287632
vt 0.017397 0.131828
vt 0.047049 0.143035
vt 0.145897 0.470132
vt 0.259541 0.470132
vt 0.232099 0.530746
vt 0.170123 0.530746
vt 0.124413 0.631713
vt 0.166266 0.676163
vt 0.228242 0.676163
vt 0.273952 0.635464
vt 0.124413 0.571445
vt 0.128161 0.425756
vt 0.279631 0.425756
vt 0.405682 0.414476
vt 0.405650 0.458926
vt 0.398680 0.458930
vt 0.398712 0.414480
vt 0.405682 0.528622
vt 0.405650 0.573072
vt 0.398680 0.573076
vt 0.398712 0.528626
vt 0.405682 0.519194
vt 0.398712 0.519197
vt 0.405682 0.633340
vt 0.398712 0.633344
vt 0.273952 0.575196
vt 0.907386 0.807523
vt 0.907386 0.747255
vt 0.933468 0.736089
vt 0.933468 0.817380
vt 0.799699 0.706556
vt 0.757846 0.751006
vt 0.731765 0.741148
vt 0.788217 0.681193
vt 0.757846 0.811274
vt 0.803557 0.851973
vt 0.793420 0.877335
vt 0.731765 0.822439
vt 0.865533 0.851973
vt 0.877016 0.877335
vt 0.413282 0.458926
vt 0.413314 0.519194
vt 0.406344 0.519197
vt 0.406312 0.458930
vt 0.421034 0.458926
vt 0.421066 0.519194
vt 0.414097 0.519197
vt 0.414065 0.458930
vt 0.421066 0.414476
vt 0.414097 0.414480
vt 0.413314 0.414476
vt 0.406344 0.414480
vt 0.783860 0.901254
vt 0.707168 0.832969
vt 0.887844 0.901254
vt 0.707168 0.731852
vt 0.871813 0.681193
vt 0.881373 0.657274
vt 0.958065 0.725559
vt 0.861676 0.706556
vt 0.059593 0.887311
vt 0.059648 0.988429
vt 0.030770 0.991625
vt 0.030712 0.884517
vt 0.997431 0.015588
vt 0.997377 0.090166
vt 0.968496 0.087372
vt 0.968554 0.008375
vt 0.997431 0.421298
vt 0.997377 0.495876
vt 0.968496 0.493081
vt 0.968554 0.414084
vt 0.997431 0.191283
vt 0.968554 0.194480
vt 0.777388 0.657274
vt 0.958065 0.826676
vt 0.940352 0.495728
vt 0.940407 0.420873
vt 0.940407 0.191512
vt 0.940352 0.090019
vt 0.968554 0.600190
vt 0.940407 0.597221
vt 0.030770 0.805520
vt 0.002569 0.887164
vt 0.002623 0.812308
vt 0.997377 0.293021
vt 0.997431 0.394138
vt 0.968554 0.397335
vt 0.968496 0.290226
vt 0.997431 0.218443
vt 0.968554 0.211229
vt 0.059648 0.812733
vt 0.997431 0.596993
vt 0.503196 0.657315
vt 0.607567 0.657315
vt 0.598599 0.679753
vt 0.513354 0.679753
vt 0.684545 0.725854
vt 0.684545 0.827347
vt 0.661471 0.818627
vt 0.661471 0.735732
vt 0.614063 0.902203
vt 0.603905 0.879765
vt 0.940407 0.015163
vt 0.002623 0.988657
vt 0.940407 0.394367
vt 0.940352 0.292873
vt 0.940407 0.218018
vt 0.576323 0.818842
vt 0.598820 0.794949
vt 0.598820 0.762553
vt 0.574250 0.740676
vt 0.455788 0.823786
vt 0.455788 0.740891
vt 0.518438 0.764569
vt 0.518438 0.796965
vt 0.518660 0.879765
vt 0.543009 0.818842
vt 0.509692 0.902203
vt 0.432714 0.833664
vt 0.432714 0.732171
vt 0.558629 0.779759
vt 0.540936 0.740676
vn -0.6110 0.7552 0.2374
vn -0.3591 0.1320 0.9239
vn -0.9239 0.1320 -0.3591
vn 0.0000 -1.0000 0.0000
vn 0.9239 0.1320 0.3591
vn 0.3591 0.1320 -0.9239
vn -0.3591 0.1320 -0.9239
vn 0.3591 0.1320 0.9239
vn 0.2374 0.7552 0.6110
vn -0.2374 0.7552 -0.6110
vn 0.9239 0.1320 -0.3591
vn -0.9239 0.1320 0.3591
vn -0.2374 0.7552 0.6110
vn -0.9309 -0.0492 0.3618
vn 0.9309 -0.0492 -0.3618
vn 0.3618 -0.0492 0.9309
vn -0.3618 -0.0492 -0.9309
vn 0.3618 -0.0492 -0.9309
vn 0.9309 -0.0492 0.3618
vn -0.9309 -0.0492 -0.3618
vn -0.3618 -0.0492 0.9309
vn -0.3591 -0.1320 0.9239
vn -0.9239 -0.1320 -0.3591
vn 0.9239 -0.1320 0.3591
vn 0.3591 -0.1320 -0.9239
vn -0.3591 -0.1320 -0.9239
vn 0.3591 -0.1320 0.9239
vn 0.9239 -0.1320 -0.3591
vn -0.9239 -0.1320 0.3591
vn -0.9309 0.0492 0.3618
vn 0.9309 0.0492 -0.3618
vn 0.3618 0.0492 0.9309
vn -0.3618 0.0492 -0.9309
vn 0.3618 0.0492 -0.9309
vn 0.9309 0.0492 0.3618
vn -0.9309 0.0492 -0.3618
vn -0.3618 0.0492 0.9309
vn -0.7464 -0.5989 0.2901
vn 0.7464 -0.5989 -0.2901
vn 0.2901 -0.5989 0.7464
vn -0.2901 -0.5989 -0.7464
vn 0.2901 -0.5989 -0.7464
vn 0.7464 -0.5989 0.2901
vn -0.7464 -0.5989 -0.2901
vn -0.2901 -0.5989 0.7464
vn -0.1811 -0.8660 0.4660
vn -0.4660 -0.8660 -0.1811
vn 0.4660 -0.8660 0.1811
vn 0.1811 -0.8660 -0.4660
vn -0.1811 -0.8660 -0.4660
vn 0.1811 -0.8660 0.4660
vn 0.4660 -0.8660 -0.1811
vn -0.4660 -0.8660 0.1811
vn 0.3268 0.9365 -0.1270
vn -0.1270 0.9365 0.3268
vn -0.3268 0.9365 -0.1270
vn 0.1270 0.9365 0.3268
vn -0.6110 0.7552 -0.2374
vn 0.6110 0.7552 0.2374
vn 0.6110 0.7552 -0.2374
vn 0.2374 0.7552 -0.6110
vn -0.3623 0.0000 0.9321
vn -0.9321 0.0000 -0.3623
vn 0.3623 0.0000 0.9321
vn -0.9321 0.0000 0.3623
vn -0.1270 0.9365 -0.3268
vn 0.1270 0.9365 -0.3268
vn 0.3268 0.9365 0.1270
vn -0.3268 0.9365 0.1270
vn -0.6386 -0.7284 0.2482
vn 0.6386 -0.7284 0.2482
vn 0.2482 -0.7284 -0.6386
vn -0.2482 -0.7284 -0.6386
vn 0.9321 0.0000 -0.3623
vn -0.3623 0.0000 -0.9321
vn 0.3623 0.0000 -0.9321
vn 0.9321 0.0000 0.3623
vn 0.2963 -0.5751 -0.7625
vn -0.2963 -0.5751 -0.7625
vn 0.7625 -0.5751 -0.2963
vn -0.2963 -0.5751 0.7625
vn 0.2482 -0.7284 0.6386
vn -0.6386 -0.7284 -0.2482
vn -0.2482 -0.7284 0.6386
vn 0.6386 -0.7284 -0.2482
vn 0.9265 -0.1091 -0.3601
vn -0.3601 -0.1091 0.9265
vn -0.9265 -0.1091 -0.3601
vn 0.3601 -0.1091 0.9265
vn 0.7625 -0.5751 0.2963
vn -0.7625 -0.5751 0.2963
vn 0.2963 -0.5751 0.7625
vn -0.7625 -0.5751 -0.2963
vn -0.9269 0.1049 -0.3603
vn 0.3603 0.1049 0.9269
vn -0.9269 0.1049 0.3603
vn 0.9269 0.1049 0.3603
vn -0.3601 -0.1091 -0.9265
vn 0.3601 -0.1091 -0.9265
vn 0.9265 -0.1091 0.3601
vn -0.9265 -0.1091 0.3601
vn 0.8334 0.4478 0.3239
vn 0.3239 0.4478 -0.8334
vn -0.3239 0.4478 -0.8334
vn 0.8334 0.4478 -0.3239
vn -0.3603 0.1049 0.9269
vn 0.9269 0.1049 -0.3603
vn -0.3603 0.1049 -0.9269
vn 0.3603 0.1049 -0.9269
vn -0.1342 0.9289 -0.3452
vn 0.3452 0.9289 -0.1342
vn -0.1342 0.9289 0.3452
vn -0.3452 0.9289 -0.1342
vn -0.8334 0.4478 0.3239
vn 0.3239 0.4478 0.8334
vn -0.8334 0.4478 -0.3239
vn -0.3239 0.4478 0.8334
vn 0.0000 1.0000 0.0000
vn 0.1342 0.9289 -0.3452
vn 0.3452 0.9289 0.1342
vn -0.3452 0.9289 0.1342
vn 0.1342 0.9289 0.3452
usemtl Material.001
s off
f 15/1/1 7/2/1 62/3/1 66/4/1
f 40/5/2 10/6/2 7/7/2 35/8/2
f 42/9/3 15/10/3 5/11/3 38/12/3
f 17/13/4 16/14/4 4/15/4 11/16/4
f 41/17/5 14/18/5 3/19/5 37/20/5
f 39/21/6 12/22/6 1/23/6 36/24/6
f 38/25/7 5/26/7 12/22/7 39/21/7
f 13/27/4 17/13/4 11/16/4 8/28/4
f 37/29/8 3/30/8 10/6/8 40/5/8
f 10/31/9 3/32/9 60/33/9 63/34/9
f 12/35/10 5/36/10 61/37/10 64/38/10
f 6/39/4 9/40/4 17/13/4 13/27/4
f 36/41/11 1/42/11 14/18/11 41/17/11
f 9/40/4 2/43/4 16/14/4 17/13/4
f 35/44/12 7/45/12 15/10/12 42/9/12
f 7/2/13 10/31/13 63/34/13 62/3/13
f 34/46/14 20/47/14 26/48/14 33/49/14
f 27/50/15 19/51/15 25/52/15 32/53/15
f 28/54/16 21/55/16 24/56/16 31/57/16
f 29/58/17 22/59/17 23/60/17 30/61/17
f 30/61/18 23/60/18 19/62/18 27/63/18
f 32/53/19 25/52/19 21/64/19 28/65/19
f 33/49/20 26/48/20 22/66/20 29/67/20
f 31/57/21 24/56/21 20/68/21 34/69/21
f 47/70/22 31/57/22 34/69/22 50/71/22
f 49/72/23 33/49/23 29/67/23 45/73/23
f 48/74/24 32/53/24 28/65/24 44/75/24
f 46/76/25 30/61/25 27/63/25 43/77/25
f 45/78/26 29/58/26 30/61/26 46/76/26
f 44/79/27 28/54/27 31/57/27 47/70/27
f 43/80/28 27/50/28 32/53/28 48/74/28
f 50/81/29 34/46/29 33/49/29 49/72/29
f 20/47/30 35/44/30 42/9/30 26/48/30
f 19/51/31 36/41/31 41/17/31 25/52/31
f 21/55/32 37/29/32 40/5/32 24/56/32
f 22/59/33 38/25/33 39/21/33 23/60/33
f 23/60/34 39/21/34 36/24/34 19/62/34
f 25/52/35 41/17/35 37/20/35 21/64/35
f 26/48/36 42/9/36 38/12/36 22/66/36
f 24/56/37 40/5/37 35/8/37 20/68/37
f 58/82/38 50/83/38 49/84/38 57/85/38
f 51/86/39 43/87/39 48/88/39 56/89/39
f 52/90/40 44/91/40 47/92/40 55/93/40
f 53/94/41 45/95/41 46/96/41 54/97/41
f 54/97/42 46/96/42 43/87/42 51/86/42
f 56/89/43 48/88/43 44/91/43 52/90/43
f 57/85/44 49/84/44 45/95/44 53/94/44
f 55/93/45 47/92/45 50/83/45 58/82/45
f 11/16/46 55/93/46 58/82/46 8/28/46
f 13/27/47 57/85/47 53/94/47 6/39/47
f 16/14/48 56/89/48 52/90/48 4/15/48
f 9/40/49 54/97/49 51/86/49 2/43/49
f 6/39/50 53/94/50 54/97/50 9/40/50
f 4/15/51 52/90/51 55/93/51 11/16/51
f 2/43/52 51/86/52 56/89/52 16/14/52
f 8/28/53 58/82/53 57/85/53 13/27/53
f 65/98/54 59/99/54 18/100/54 73/101/54
f 62/3/55 63/34/55 71/102/55 70/103/55
f 61/37/56 66/4/56 74/104/56 69/105/56
f 63/34/57 60/33/57 68/106/57 71/102/57
f 5/36/58 15/1/58 66/4/58 61/37/58
f 3/32/59 14/107/59 65/98/59 60/33/59
f 14/107/60 1/108/60 59/99/60 65/98/60
f 1/108/61 12/35/61 64/38/61 59/99/61
f 70/109/62 71/110/62 79/111/62 78/112/62
f 69/113/63 74/114/63 82/115/63 77/116/63
f 71/110/64 68/117/64 76/118/64 79/111/64
f 74/114/65 70/119/65 78/120/65 82/115/65
f 64/38/66 61/37/66 69/105/66 72/121/66
f 59/99/67 64/38/67 72/121/67 18/100/67
f 60/33/68 65/98/68 73/101/68 68/106/68
f 66/4/69 62/3/69 70/103/69 74/104/69
f 82/122/70 78/123/70 86/124/70 90/125/70
f 76/126/71 81/127/71 89/128/71 84/129/71
f 67/130/72 80/131/72 88/132/72 75/133/72
f 80/131/73 77/134/73 85/135/73 88/132/73
f 73/136/74 18/137/74 67/138/74 81/139/74
f 72/140/75 69/141/75 77/142/75 80/143/75
f 18/144/76 72/140/76 80/143/76 67/145/76
f 68/146/77 73/136/77 81/139/77 76/147/77
f 75/133/78 88/132/78 96/148/78 83/149/78
f 88/132/79 85/135/79 93/150/79 96/148/79
f 89/128/80 75/133/80 83/149/80 97/151/80
f 86/124/81 87/152/81 95/153/81 94/154/81
f 79/155/82 76/126/82 84/129/82 87/152/82
f 77/134/83 82/122/83 90/125/83 85/135/83
f 78/123/84 79/155/84 87/152/84 86/124/84
f 81/127/85 67/130/85 75/133/85 89/128/85
f 97/156/86 83/157/86 91/158/86 105/159/86
f 94/160/87 95/161/87 103/162/87 102/163/87
f 93/164/88 98/165/88 106/166/88 101/167/88
f 95/161/89 92/168/89 100/169/89 103/162/89
f 84/129/90 89/128/90 97/151/90 92/170/90
f 90/125/91 86/124/91 94/154/91 98/171/91
f 87/152/92 84/129/92 92/170/92 95/153/92
f 85/135/93 90/125/93 98/171/93 93/150/93
f 101/167/94 106/166/94 114/172/94 109/173/94
f 103/162/95 100/169/95 108/174/95 111/175/95
f 106/166/96 102/176/96 110/177/96 114/172/96
f 100/178/97 105/159/97 113/179/97 108/180/97
f 96/181/98 93/182/98 101/183/98 104/184/98
f 83/185/99 96/181/99 104/184/99 91/186/99
f 92/187/100 97/156/100 105/159/100 100/178/100
f 98/165/101 94/188/101 102/176/101 106/166/101
f 108/189/102 113/190/102 121/191/102 116/192/102
f 99/193/103 112/194/103 120/195/103 107/196/103
f 112/194/104 109/197/104 117/198/104 120/195/104
f 113/190/105 99/193/105 107/196/105 121/191/105
f 102/163/106 103/162/106 111/175/106 110/199/106
f 105/159/107 91/158/107 99/200/107 113/179/107
f 104/184/108 101/183/108 109/201/108 112/202/108
f 91/186/109 104/184/109 112/202/109 99/203/109
f 120/195/110 117/198/110 124/204/110 127/205/110
f 121/191/111 107/196/111 115/206/111 128/207/111
f 118/208/112 119/209/112 126/210/112 125/211/112
f 117/198/113 122/212/113 129/213/113 124/204/113
f 114/214/114 110/215/114 118/208/114 122/212/114
f 111/216/115 108/189/115 116/192/115 119/209/115
f 109/197/116 114/214/116 122/212/116 117/198/116
f 110/215/117 111/216/117 119/209/117 118/208/117
f 130/217/118 129/213/118 125/211/118 126/210/118
f 128/207/118 130/217/118 126/210/118 123/218/118
f 115/206/118 127/205/118 130/217/118 128/207/118
f 127/205/118 124/204/118 129/213/118 130/217/118
f 107/196/119 120/195/119 127/205/119 115/206/119
f 116/192/120 121/191/120 128/207/120 123/218/120
f 122/212/121 118/208/121 125/211/121 129/213/121
f 119/209/122 116/192/122 123/218/122 126/210/122

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,20 @@
#version 460 core
in vec2 textureCoords;
in vec3 vertexNormal;
out vec4 fragmentColor;
uniform sampler2D textureSampler;
void main() {
vec4 baseColor = texture(textureSampler, textureCoords);
vec3 lightDirection = normalize(vec3(0.5, -1.0, -0.5));// TODO: Add this via a uniform.
vec3 lightColor = vec3(1.0, 1.0, 0.9); // TODO: Add this via a uniform.
vec3 ambientComponent = vec3(0.1, 0.1, 0.1);
vec3 diffuseComponent = max(dot(vertexNormal * -1, lightDirection), 0.0) * lightColor;
// TODO: Add shading based on light.
// fragmentColor = vec4((ambientComponent + diffuseComponent), 1.0) * baseColor;
fragmentColor = baseColor;
}

View File

@ -0,0 +1,18 @@
#version 460 core
layout (location = 0) in vec3 vertexPositionIn;
layout (location = 1) in vec3 vertexNormalIn;
layout (location = 2) in vec2 textureCoordsIn;
uniform mat4 projectionTransform;
uniform mat4 viewTransform;
uniform mat4 modelTransform;
out vec2 textureCoords;
out vec3 vertexNormal;
void main() {
gl_Position = projectionTransform * viewTransform * modelTransform * vec4(vertexPositionIn, 1.0);
vertexNormal = vec3(modelTransform * vec4(vertexNormalIn, 1.0));
textureCoords = textureCoordsIn;
}

View File

@ -16,7 +16,7 @@ public class ImageUtils {
// ARGB format to -> RGBA // ARGB format to -> RGBA
for( int h = 0; h < height; h++ ) for( int h = 0; h < height; h++ )
for( int w = 0; w < width; w++ ) { for( int w = 0; w < width; w++ ) {
int argb = image.getRGB( w, h ); int argb = image.getRGB(w, h);
buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) ); buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) ); buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) );
buf.put( (byte) ( 0xFF & ( argb ) ) ); buf.put( (byte) ( 0xFF & ( argb ) ) );
@ -25,4 +25,14 @@ public class ImageUtils {
buf.flip(); buf.flip();
return buf; return buf;
} }
public static BufferedImage rotateClockwise90(BufferedImage src) {
int w = src.getWidth();
int h = src.getHeight();
BufferedImage dest = new BufferedImage(h, w, src.getType());
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
dest.setRGB(y, w - x - 1, src.getRGB(x, y));
return dest;
}
} }

View File

@ -1,7 +1,6 @@
package nl.andrewl.aos_core.model; package nl.andrewl.aos_core.model;
import net.openhft.hashing.LongHashFunction; import net.openhft.hashing.LongHashFunction;
import org.joml.Vector3f;
import org.joml.Vector3i; import org.joml.Vector3i;
import java.util.Random; import java.util.Random;
@ -115,6 +114,11 @@ public class Chunk {
return sb.toString(); return sb.toString();
} }
@Override
public int hashCode() {
return position.hashCode();
}
public long blockHash() { public long blockHash() {
return LongHashFunction.xx3(0).hashBytes(blocks); return LongHashFunction.xx3(0).hashBytes(blocks);
} }

View File

@ -21,4 +21,12 @@ public record PlayerJoinMessage(
player.getOrientation().x, player.getOrientation().y player.getOrientation().x, player.getOrientation().y
); );
} }
public Player toPlayer() {
Player p = new Player(id, username);
p.getPosition().set(px, py, pz);
p.getVelocity().set(vx, vy, vz);
p.getOrientation().set(ox, oy);
return p;
}
} }

View File

@ -35,7 +35,6 @@ public class UdpReceiver implements Runnable {
handler.handle(msg, packet); handler.handle(msg, packet);
} catch (SocketException e) { } catch (SocketException e) {
if (e.getMessage().equals("Socket closed")) { if (e.getMessage().equals("Socket closed")) {
System.out.println("Socket closed!");
break; break;
} }
e.printStackTrace(); e.printStackTrace();

View File

@ -28,4 +28,12 @@ public record ChunkUpdateMessage(
world.getBlockAt(worldPos.x, worldPos.y, worldPos.z) world.getBlockAt(worldPos.x, worldPos.y, worldPos.z)
); );
} }
public Vector3i getChunkPos() {
return new Vector3i(cx, cy, cz);
}
public Vector3i getLocalPos() {
return new Vector3i(lx, ly, lz);
}
} }

View File

@ -1,5 +1,6 @@
package nl.andrewl.aos_core.net.udp; package nl.andrewl.aos_core.net.udp;
import nl.andrewl.aos_core.model.Player;
import nl.andrewl.record_net.Message; import nl.andrewl.record_net.Message;
/** /**
@ -12,4 +13,11 @@ public record PlayerUpdateMessage(
float vx, float vy, float vz, float vx, float vy, float vz,
float ox, float oy, float ox, float oy,
boolean crouching boolean crouching
) implements Message {} ) implements Message {
public void apply(Player p) {
p.getPosition().set(px, py, pz);
p.getVelocity().set(vx, vy, vz);
p.getOrientation().set(ox, oy);
}
}

View File

@ -91,6 +91,13 @@ public class ClientCommunicationHandler {
log.debug("Sent connect accept message."); log.debug("Sent connect accept message.");
sendTcpMessage(new WorldInfoMessage(server.getWorld())); sendTcpMessage(new WorldInfoMessage(server.getWorld()));
// Send join info for all players that are already connected.
for (var player : server.getPlayerManager().getPlayers()) {
if (player.getId() != this.player.getId()) {
sendTcpMessage(new PlayerJoinMessage(player));
}
}
// Send chunk data.
for (var chunk : server.getWorld().getChunkMap().values()) { for (var chunk : server.getWorld().getChunkMap().values()) {
sendTcpMessage(new ChunkDataMessage(chunk)); sendTcpMessage(new ChunkDataMessage(chunk));
} }