Added erroneous but somewhat working example.
This commit is contained in:
parent
969576b34d
commit
d34a4aa017
|
@ -212,4 +212,31 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>nl.andrewl.aos2_client.Aos2Client</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
|
@ -1,5 +1,7 @@
|
||||||
package nl.andrewl.aos2_client;
|
package nl.andrewl.aos2_client;
|
||||||
|
|
||||||
|
import nl.andrewl.aos2_client.render.ChunkMesh;
|
||||||
|
import nl.andrewl.aos2_client.render.ChunkRenderer;
|
||||||
import nl.andrewl.aos_core.model.Chunk;
|
import nl.andrewl.aos_core.model.Chunk;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
import org.lwjgl.Version;
|
import org.lwjgl.Version;
|
||||||
|
@ -19,29 +21,28 @@ public class Aos2Client {
|
||||||
long windowHandle = initUI();
|
long windowHandle = initUI();
|
||||||
|
|
||||||
Camera cam = new Camera();
|
Camera cam = new Camera();
|
||||||
|
cam.setOrientationDegrees(90, 90);
|
||||||
|
cam.setPosition(-3, 3, 0);
|
||||||
glfwSetCursorPosCallback(windowHandle, cam);
|
glfwSetCursorPosCallback(windowHandle, cam);
|
||||||
|
|
||||||
Chunk chunk = Chunk.random(new Vector3i(0, 0, 0), new Random(1));
|
Chunk chunk = Chunk.random(new Vector3i(0, 0, 0), new Random(1));
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
chunk.setBlockAt(i, 0, 0, (byte) 8);
|
|
||||||
chunk.setBlockAt(0, i, 0, (byte) 40);
|
|
||||||
chunk.setBlockAt(0, 0, i, (byte) 120);
|
|
||||||
}
|
|
||||||
// chunk.setBlockAt(0, 15, 0, (byte) 0);
|
|
||||||
// chunk.setBlockAt(1, 15, 0, (byte) 0);
|
|
||||||
// chunk.setBlockAt(2, 15, 0, (byte) 0);
|
|
||||||
// chunk.setBlockAt(2, 15, 1, (byte) 0);
|
|
||||||
// chunk.setBlockAt(0, 0, 0, (byte) 0);
|
|
||||||
Chunk chunk2 = Chunk.random(new Vector3i(1, 0, 0), new Random(1));
|
Chunk chunk2 = Chunk.random(new Vector3i(1, 0, 0), new Random(1));
|
||||||
Chunk chunk3 = Chunk.random(new Vector3i(1, 0, 1), new Random(1));
|
Chunk chunk3 = Chunk.random(new Vector3i(1, 0, 1), new Random(1));
|
||||||
Chunk chunk4 = Chunk.random(new Vector3i(0, 0, 1), new Random(1));
|
Chunk chunk4 = Chunk.random(new Vector3i(0, 0, 1), new Random(1));
|
||||||
|
|
||||||
ChunkRenderer chunkRenderer = new ChunkRenderer();
|
// chunk.setBlockAt(0, 0, 0, (byte) 0);
|
||||||
|
|
||||||
|
for (int x = 0; x < Chunk.SIZE; x++) {
|
||||||
|
for (int z = 0; z < Chunk.SIZE; z++) {
|
||||||
|
chunk.setBlockAt(x, Chunk.SIZE - 1, z, (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkRenderer chunkRenderer = new ChunkRenderer();
|
||||||
|
chunkRenderer.addChunkMesh(new ChunkMesh(chunk));
|
||||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk2));
|
chunkRenderer.addChunkMesh(new ChunkMesh(chunk2));
|
||||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk3));
|
chunkRenderer.addChunkMesh(new ChunkMesh(chunk3));
|
||||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk4));
|
chunkRenderer.addChunkMesh(new ChunkMesh(chunk4));
|
||||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk));
|
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(windowHandle)) {
|
while (!glfwWindowShouldClose(windowHandle)) {
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -94,7 +95,7 @@ public class Aos2Client {
|
||||||
glfwShowWindow(windowHandle);
|
glfwShowWindow(windowHandle);
|
||||||
|
|
||||||
GL.createCapabilities();
|
GL.createCapabilities();
|
||||||
GLUtil.setupDebugMessageCallback(System.out);
|
// GLUtil.setupDebugMessageCallback(System.out);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
|
@ -8,6 +8,9 @@ import org.lwjgl.glfw.GLFWCursorPosCallbackI;
|
||||||
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
|
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the player camera in the game world.
|
||||||
|
*/
|
||||||
public class Camera implements GLFWCursorPosCallbackI {
|
public class Camera implements GLFWCursorPosCallbackI {
|
||||||
public static final Vector3f UP = new Vector3f(0, 1, 0);
|
public static final Vector3f UP = new Vector3f(0, 1, 0);
|
||||||
public static final Vector3f DOWN = new Vector3f(0, -1, 0);
|
public static final Vector3f DOWN = new Vector3f(0, -1, 0);
|
||||||
|
@ -16,7 +19,23 @@ public class Camera implements GLFWCursorPosCallbackI {
|
||||||
public static final Vector3f FORWARD = new Vector3f(0, 0, -1);
|
public static final Vector3f FORWARD = new Vector3f(0, 0, -1);
|
||||||
public static final Vector3f BACKWARD = new Vector3f(0, 0, 1);
|
public static final Vector3f BACKWARD = new Vector3f(0, 0, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x, y, and z position of the camera in the world.
|
||||||
|
*/
|
||||||
private final Vector3f position;
|
private final Vector3f position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The camera's angular orientation. X refers to the rotation about the
|
||||||
|
* vertical axis, while Y refers to the rotation about the horizontal axis.
|
||||||
|
* <p>
|
||||||
|
* The Y axis orientation is limited to between 0 and PI, with 0
|
||||||
|
* being looking straight down, and PI looking straight up.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The X axis orientation is limited to between 0 and 2 PI, with 0
|
||||||
|
* being looking at the - Z axis.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
private final Vector2f orientation;
|
private final Vector2f orientation;
|
||||||
private final Matrix4f viewTransform;
|
private final Matrix4f viewTransform;
|
||||||
private final float[] viewTransformData = new float[16];
|
private final float[] viewTransformData = new float[16];
|
||||||
|
@ -50,7 +69,10 @@ public class Camera implements GLFWCursorPosCallbackI {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrientation(float x, float y) {
|
public void setOrientation(float x, float y) {
|
||||||
orientation.set(MathUtils.normalize(x, 0, Math.PI * 2), MathUtils.normalize(y, 0, Math.PI * 2));
|
orientation.set(
|
||||||
|
MathUtils.normalize(x, 0, Math.PI * 2),
|
||||||
|
MathUtils.clamp(y, 0, (float) (Math.PI))
|
||||||
|
);
|
||||||
updateViewTransform();
|
updateViewTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +82,7 @@ public class Camera implements GLFWCursorPosCallbackI {
|
||||||
|
|
||||||
private void updateViewTransform() {
|
private void updateViewTransform() {
|
||||||
viewTransform.identity();
|
viewTransform.identity();
|
||||||
viewTransform.rotate(-orientation.y, RIGHT);
|
viewTransform.rotate(-orientation.y + ((float) Math.PI / 2), RIGHT);
|
||||||
viewTransform.rotate(-orientation.x, UP);
|
viewTransform.rotate(-orientation.x, UP);
|
||||||
viewTransform.translate(-position.x, -position.y, -position.z);
|
viewTransform.translate(-position.x, -position.y, -position.z);
|
||||||
viewTransform.get(viewTransformData);
|
viewTransform.get(viewTransformData);
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
package nl.andrewl.aos2_client;
|
|
||||||
|
|
||||||
import nl.andrewl.aos_core.Pair;
|
|
||||||
import nl.andrewl.aos_core.model.Chunk;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.joml.Vector3i;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL46.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a 3d mesh for a chunk.
|
|
||||||
*/
|
|
||||||
public class ChunkMesh {
|
|
||||||
private final int vboId;
|
|
||||||
private final int vaoId;
|
|
||||||
private final int eboId;
|
|
||||||
|
|
||||||
private int indiciesCount;
|
|
||||||
|
|
||||||
private final int[] positionData;
|
|
||||||
|
|
||||||
public ChunkMesh(Chunk chunk) {
|
|
||||||
this.positionData = new int[]{chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z};
|
|
||||||
this.vboId = glGenBuffers();
|
|
||||||
this.vaoId = glGenVertexArrays();
|
|
||||||
this.eboId = glGenBuffers();
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
var meshData = generateMesh(chunk);
|
|
||||||
long dur = System.currentTimeMillis() - start;
|
|
||||||
System.out.println("Generated chunk mesh in " + dur + " ms");
|
|
||||||
this.indiciesCount = meshData.second().length;
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, meshData.first(), GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshData.second(), GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pair<float[], int[]> generateMesh(Chunk c) {
|
|
||||||
List<BlockVertexData> vertexList = new ArrayList<>();
|
|
||||||
List<Integer> indexList = new ArrayList<>();
|
|
||||||
int idx = 0;
|
|
||||||
for (int x = 0; x < Chunk.SIZE; x++) {
|
|
||||||
for (int y = 0; y < Chunk.SIZE; y++) {
|
|
||||||
for (int z = 0; z < Chunk.SIZE; z++) {
|
|
||||||
byte block = c.getBlockAt(x, y, z);
|
|
||||||
if (block == 0) continue;
|
|
||||||
Vector3f color = Chunk.getColor(block);
|
|
||||||
var A = new Vector3f(x, y + 1, z);
|
|
||||||
var B = new Vector3f(x, y + 1, z + 1);
|
|
||||||
var C = new Vector3f(x + 1, y + 1, z + 1);
|
|
||||||
var D = new Vector3f(x + 1, y + 1, z);
|
|
||||||
var E = new Vector3f(x, y, z);
|
|
||||||
var F = new Vector3f(x, y, z + 1);
|
|
||||||
var G = new Vector3f(x + 1, y, z + 1);
|
|
||||||
var H = new Vector3f(x + 1, y, z);
|
|
||||||
|
|
||||||
// Top
|
|
||||||
if (c.getBlockAt(x, y + 1, z) == 0) {
|
|
||||||
var norm = new Vector3f(0, 1, 0);
|
|
||||||
vertexList.addAll(Stream.of(A, B, C, D).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx, idx + 1, idx + 3,
|
|
||||||
idx + 3, idx + 1, idx + 2
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
// Bottom
|
|
||||||
if (c.getBlockAt(x, y - 1, z) == 0) {
|
|
||||||
var norm = new Vector3f(0, -1, 0);
|
|
||||||
vertexList.addAll(Stream.of(E, F, G, H).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx + 3, idx + 1, idx,
|
|
||||||
idx + 1, idx + 3, idx + 2
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
// Positive z
|
|
||||||
if (c.getBlockAt(x, y, z + 1) == 0) {
|
|
||||||
var norm = new Vector3f(0, 0, 1);
|
|
||||||
vertexList.addAll(Stream.of(B, F, G, C).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx + 3, idx, idx + 1,
|
|
||||||
idx + 3, idx + 1, idx + 2
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
// Negative z
|
|
||||||
if (c.getBlockAt(x, y, z - 1) == 0) {
|
|
||||||
var norm = new Vector3f(0, 0, -1);
|
|
||||||
vertexList.addAll(Stream.of(A, E, H, D).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx, idx + 3, idx + 2,
|
|
||||||
idx + 2, idx + 1, idx
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
// Positive x
|
|
||||||
if (c.getBlockAt(x + 1, y, z) == 0) {
|
|
||||||
var norm = new Vector3f(1, 0, 0);
|
|
||||||
vertexList.addAll(Stream.of(C, G, H, D).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx + 3, idx, idx + 1,
|
|
||||||
idx + 3, idx + 1, idx + 2
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
// Negative x
|
|
||||||
if (c.getBlockAt(x - 1, y, z) == 0) {
|
|
||||||
var norm = new Vector3f(-1, 0, 0);
|
|
||||||
vertexList.addAll(Stream.of(A, E, F, B).map(v -> new BlockVertexData(v, color, norm)).toList());
|
|
||||||
indexList.addAll(List.of(
|
|
||||||
idx + 3, idx, idx + 1,
|
|
||||||
idx + 3, idx + 1, idx + 2
|
|
||||||
));
|
|
||||||
idx += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] vertexData = new float[9 * vertexList.size()];
|
|
||||||
int vertexDataIdx = 0;
|
|
||||||
for (var vertex : vertexList) {
|
|
||||||
vertexData[vertexDataIdx++] = vertex.position().x;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.position().y;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.position().z;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.color().x;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.color().y;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.color().z;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.normal().x;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.normal().y;
|
|
||||||
vertexData[vertexDataIdx++] = vertex.normal().z;
|
|
||||||
}
|
|
||||||
int[] indexData = indexList.stream().mapToInt(v -> v).toArray();
|
|
||||||
System.out.printf("Generated chunk mesh: %d vertices, %d indexes%n", vertexList.size(), indexData.length);
|
|
||||||
|
|
||||||
return new Pair<>(vertexData, indexData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getPositionData() {
|
|
||||||
return positionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void draw() {
|
|
||||||
// Bind elements.
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
|
|
||||||
glBindVertexArray(vaoId);
|
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, indiciesCount, GL_UNSIGNED_INT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void free() {
|
|
||||||
glDeleteBuffers(vboId);
|
|
||||||
glDeleteBuffers(eboId);
|
|
||||||
glDeleteVertexArrays(vaoId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.andrewl.aos2_client;
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
|
import nl.andrewl.aos_core.model.Chunk;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL46.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a 3d mesh for a chunk.
|
||||||
|
*/
|
||||||
|
public class ChunkMesh {
|
||||||
|
private final int vboId;
|
||||||
|
private final int vaoId;
|
||||||
|
private final int eboId;
|
||||||
|
|
||||||
|
private int indiciesCount;
|
||||||
|
|
||||||
|
private final int[] positionData;
|
||||||
|
private final Chunk chunk;
|
||||||
|
|
||||||
|
public ChunkMesh(Chunk chunk) {
|
||||||
|
this.chunk = chunk;
|
||||||
|
this.positionData = new int[]{chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z};
|
||||||
|
|
||||||
|
this.vboId = glGenBuffers();
|
||||||
|
this.eboId = glGenBuffers();
|
||||||
|
this.vaoId = glGenVertexArrays();
|
||||||
|
|
||||||
|
loadMesh();
|
||||||
|
|
||||||
|
initVertexArrayAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getPositionData() {
|
||||||
|
return positionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadMesh() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
var meshData = ChunkMeshGenerator.generateMesh(chunk);
|
||||||
|
long dur = System.currentTimeMillis() - start;
|
||||||
|
System.out.printf(
|
||||||
|
"Generated chunk mesh in %d ms with %d vertices and %d indices, and %d faces. Vertex data size: %d%n",
|
||||||
|
dur,
|
||||||
|
meshData.vertexData().limit() / 9,
|
||||||
|
meshData.indices().limit(),
|
||||||
|
meshData.indices().limit() / 4,
|
||||||
|
meshData.vertexData().limit()
|
||||||
|
);
|
||||||
|
this.indiciesCount = meshData.indices().limit();
|
||||||
|
int[] data = new int[indiciesCount];
|
||||||
|
meshData.indices().get(data);
|
||||||
|
meshData.indices().flip();
|
||||||
|
System.out.println(Arrays.toString(data));
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, meshData.vertexData(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshData.indices(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
int size = glGetBufferParameteri(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE);
|
||||||
|
System.out.println(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||||
|
glBindVertexArray(vaoId);
|
||||||
|
glDrawElements(GL_TRIANGLES, indiciesCount, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
glDeleteBuffers(vboId);
|
||||||
|
glDeleteBuffers(eboId);
|
||||||
|
glDeleteVertexArrays(vaoId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
public record ChunkMeshData(
|
||||||
|
FloatBuffer vertexData,
|
||||||
|
IntBuffer indices
|
||||||
|
) {}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
|
import nl.andrewl.aos_core.model.Chunk;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public final class ChunkMeshGenerator {
|
||||||
|
private ChunkMeshGenerator() {}
|
||||||
|
|
||||||
|
public static ChunkMeshData generateMesh(Chunk chunk) {
|
||||||
|
FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(20000);
|
||||||
|
IntBuffer indexBuffer = BufferUtils.createIntBuffer(5000);
|
||||||
|
int idx = 0;
|
||||||
|
for (int i = 0; i < Chunk.TOTAL_SIZE; i++) {
|
||||||
|
var pos = Chunk.idxToXyz(i);
|
||||||
|
int x = pos.x;
|
||||||
|
int y = pos.y;
|
||||||
|
int z = pos.z;
|
||||||
|
byte block = chunk.getBlocks()[i];
|
||||||
|
if (block <= 0) {
|
||||||
|
continue; // Don't render empty blocks.
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f color = Chunk.getColor(block);
|
||||||
|
|
||||||
|
// See /design/block_rendering.svg for a diagram of how these vertices are defined.
|
||||||
|
var a = new Vector3f(x, y + 1, z + 1);
|
||||||
|
var b = new Vector3f(x, y + 1, z);
|
||||||
|
var c = new Vector3f(x, y, z);
|
||||||
|
var d = new Vector3f(x, y, z + 1);
|
||||||
|
var e = new Vector3f(x + 1, y + 1, z);
|
||||||
|
var f = new Vector3f(x + 1, y + 1, z + 1);
|
||||||
|
var g = new Vector3f(x + 1, y, z + 1);
|
||||||
|
var h = new Vector3f(x + 1, y, z);
|
||||||
|
|
||||||
|
// Top
|
||||||
|
if (chunk.getBlockAt(x, y + 1, z) == 0) {
|
||||||
|
var norm = new Vector3f(0, 1, 0);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(a, f, e, b));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
// Bottom
|
||||||
|
if (chunk.getBlockAt(x, y - 1, z) == 0) {
|
||||||
|
var norm = new Vector3f(0, -1, 0);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(c, h, g, d));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
// Positive z
|
||||||
|
if (chunk.getBlockAt(x, y, z + 1) == 0) {
|
||||||
|
var norm = new Vector3f(0, 0, 1);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(f, a, d, g));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
// Negative z
|
||||||
|
if (chunk.getBlockAt(x, y, z - 1) == 0) {
|
||||||
|
var norm = new Vector3f(0, 0, -1);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(b, e, h, c));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
// Positive x
|
||||||
|
if (chunk.getBlockAt(x + 1, y, z) == 0) {
|
||||||
|
var norm = new Vector3f(1, 0, 0);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(e, f, g, h));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
// Negative x
|
||||||
|
if (chunk.getBlockAt(x - 1, y, z) == 0) {
|
||||||
|
var norm = new Vector3f(-1, 0, 0);
|
||||||
|
genFace(vertexBuffer, indexBuffer, idx, color, norm, List.of(a, b, c, d));
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ChunkMeshData(vertexBuffer.flip(), indexBuffer.flip());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void genFace(FloatBuffer vertexBuffer, IntBuffer indexBuffer, int currentIndex, Vector3f color, Vector3f norm, List<Vector3f> vertices) {
|
||||||
|
for (var vertex : vertices) {
|
||||||
|
vertexBuffer.put(vertex.x);
|
||||||
|
vertexBuffer.put(vertex.y);
|
||||||
|
vertexBuffer.put(vertex.z);
|
||||||
|
vertexBuffer.put(color.x);
|
||||||
|
vertexBuffer.put(color.y);
|
||||||
|
vertexBuffer.put(color.z);
|
||||||
|
vertexBuffer.put(norm.x);
|
||||||
|
vertexBuffer.put(norm.y);
|
||||||
|
vertexBuffer.put(norm.z);
|
||||||
|
}
|
||||||
|
// Top-left triangle.
|
||||||
|
indexBuffer.put(currentIndex);
|
||||||
|
indexBuffer.put(currentIndex + 1);
|
||||||
|
indexBuffer.put(currentIndex + 2);
|
||||||
|
// Bottom-right triangle.
|
||||||
|
indexBuffer.put(currentIndex + 2);
|
||||||
|
indexBuffer.put(currentIndex + 3);
|
||||||
|
indexBuffer.put(currentIndex);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package nl.andrewl.aos2_client;
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
|
import nl.andrewl.aos2_client.Camera;
|
||||||
|
import nl.andrewl.aos_core.model.Chunk;
|
||||||
import org.joml.Matrix3f;
|
import org.joml.Matrix3f;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ public class ChunkRenderer {
|
||||||
private final int viewTransformUniform;
|
private final int viewTransformUniform;
|
||||||
private final int normalTransformUniform;
|
private final int normalTransformUniform;
|
||||||
private final int chunkPositionUniform;
|
private final int chunkPositionUniform;
|
||||||
|
private final int chunkSizeUniform;
|
||||||
|
|
||||||
private final Matrix4f projectionTransform = new Matrix4f().perspective(70, 800 / 600.0f, 0.01f, 100.0f);
|
private final Matrix4f projectionTransform = new Matrix4f().perspective(70, 800 / 600.0f, 0.01f, 100.0f);
|
||||||
|
|
||||||
|
@ -22,16 +25,18 @@ public class ChunkRenderer {
|
||||||
public ChunkRenderer() {
|
public ChunkRenderer() {
|
||||||
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/normal_fragment.glsl", GL_FRAGMENT_SHADER)
|
||||||
.build();
|
.build();
|
||||||
shaderProgram.use();
|
shaderProgram.use();
|
||||||
this.projectionTransformUniform = shaderProgram.getUniform("projectionTransform");
|
this.projectionTransformUniform = shaderProgram.getUniform("projectionTransform");
|
||||||
this.viewTransformUniform = shaderProgram.getUniform("viewTransform");
|
this.viewTransformUniform = shaderProgram.getUniform("viewTransform");
|
||||||
this.normalTransformUniform = shaderProgram.getUniform("normalTransform");
|
this.normalTransformUniform = shaderProgram.getUniform("normalTransform");
|
||||||
this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition");
|
this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition");
|
||||||
|
this.chunkSizeUniform = shaderProgram.getUniform("chunkSize");
|
||||||
|
|
||||||
// Preemptively load projection transform, which doesn't change much.
|
// Preemptively load projection transform, which doesn't change much.
|
||||||
glUniformMatrix4fv(projectionTransformUniform, false, projectionTransform.get(new float[16]));
|
glUniformMatrix4fv(projectionTransformUniform, false, projectionTransform.get(new float[16]));
|
||||||
|
glUniform1i(chunkSizeUniform, Chunk.SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChunkMesh(ChunkMesh mesh) {
|
public void addChunkMesh(ChunkMesh mesh) {
|
||||||
|
@ -39,13 +44,9 @@ public class ChunkRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Camera cam) {
|
public void draw(Camera cam) {
|
||||||
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
|
|
||||||
Matrix3f normalTransform = new Matrix3f();
|
|
||||||
glUniformMatrix3fv(normalTransformUniform, false, normalTransform.get(new float[9]));
|
|
||||||
shaderProgram.use();
|
shaderProgram.use();
|
||||||
|
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
|
||||||
for (var mesh : chunkMeshes) {
|
for (var mesh : chunkMeshes) {
|
||||||
// For each chunk, specify its position so that the shaders can draw it offset.
|
|
||||||
glUniform3iv(chunkPositionUniform, mesh.getPositionData());
|
glUniform3iv(chunkPositionUniform, mesh.getPositionData());
|
||||||
mesh.draw();
|
mesh.draw();
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.andrewl.aos2_client;
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
import nl.andrewl.aos_core.FileUtils;
|
import nl.andrewl.aos_core.FileUtils;
|
||||||
|
|
||||||
|
@ -10,12 +10,20 @@ import static org.lwjgl.opengl.GL46.*;
|
||||||
* Represents a shader program with one or more individual shaders.
|
* Represents a shader program with one or more individual shaders.
|
||||||
*/
|
*/
|
||||||
public class ShaderProgram {
|
public class ShaderProgram {
|
||||||
|
/**
|
||||||
|
* The id of the generated shader program.
|
||||||
|
*/
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
public ShaderProgram(int id) {
|
public ShaderProgram(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to set this program as the one currently used by the OpenGL
|
||||||
|
* context. Call this before any other operation which uses the program,
|
||||||
|
* like {@link ShaderProgram#getUniform(String)} or drawing.
|
||||||
|
*/
|
||||||
public void use() {
|
public void use() {
|
||||||
glUseProgram(id);
|
glUseProgram(id);
|
||||||
}
|
}
|
||||||
|
@ -53,5 +61,9 @@ public class ShaderProgram {
|
||||||
glLinkProgram(id);
|
glLinkProgram(id);
|
||||||
return new ShaderProgram(id);
|
return new ShaderProgram(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void discard() {
|
||||||
|
glDeleteProgram(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.andrewl.aos2_client;
|
package nl.andrewl.aos2_client.render;
|
||||||
|
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.BufferUtils;
|
|
@ -15,5 +15,4 @@ void main() {
|
||||||
// No specular component.
|
// No specular component.
|
||||||
|
|
||||||
fragmentColor = vec4((ambientComponent + diffuseComponent) * vertexColor, 1.0);
|
fragmentColor = vec4((ambientComponent + diffuseComponent) * vertexColor, 1.0);
|
||||||
//fragmentColor = vec4((vertexNormal + 1) / 2.0, 1.0);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
in vec3 vertexColor;
|
||||||
|
in vec3 vertexNormal;
|
||||||
|
|
||||||
|
out vec4 fragmentColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragmentColor = vec4((vertexNormal + 1) / 2.0, 1.0);
|
||||||
|
}
|
|
@ -6,18 +6,17 @@ layout (location = 2) in vec3 vertexNormalIn;
|
||||||
|
|
||||||
uniform mat4 projectionTransform;
|
uniform mat4 projectionTransform;
|
||||||
uniform mat4 viewTransform;
|
uniform mat4 viewTransform;
|
||||||
uniform mat3 normalTransform;
|
|
||||||
uniform ivec3 chunkPosition;
|
uniform ivec3 chunkPosition;
|
||||||
|
uniform int chunkSize;
|
||||||
|
|
||||||
out vec3 vertexPosition;
|
out vec3 vertexPosition;
|
||||||
out vec3 vertexColor;
|
out vec3 vertexColor;
|
||||||
out vec3 vertexNormal;
|
out vec3 vertexNormal;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 realVertexPosition = vertexPositionIn + (chunkPosition * 16);
|
vertexPosition = vertexPositionIn + (chunkPosition * chunkSize);
|
||||||
|
|
||||||
gl_Position = projectionTransform * viewTransform * vec4(realVertexPosition, 1.0);
|
gl_Position = projectionTransform * viewTransform * vec4(vertexPosition, 1.0);
|
||||||
vertexPosition = realVertexPosition;
|
|
||||||
vertexColor = vertexColorIn;
|
vertexColor = vertexColorIn;
|
||||||
vertexNormal = normalize(normalTransform * vertexNormalIn);
|
vertexNormal = vertexNormalIn;
|
||||||
}
|
}
|
||||||
|
|
15
core/pom.xml
15
core/pom.xml
|
@ -23,5 +23,20 @@
|
||||||
<artifactId>joml</artifactId>
|
<artifactId>joml</artifactId>
|
||||||
<version>1.10.4</version>
|
<version>1.10.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
|
@ -6,4 +6,15 @@ public class MathUtils {
|
||||||
final double offsetValue = value - start;
|
final double offsetValue = value - start;
|
||||||
return offsetValue - (Math.floor(offsetValue / width) * width) + start;
|
return offsetValue - (Math.floor(offsetValue / width) * width) + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float normalize(float value, float start, float end) {
|
||||||
|
final float width = end - start;
|
||||||
|
final float offsetValue = value - start;
|
||||||
|
return offsetValue - ((float) Math.floor(offsetValue / width) * width) + start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float clamp(float value, float min, float max) {
|
||||||
|
if (value < min) return min;
|
||||||
|
return Math.min(value, max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class Chunk {
|
||||||
/**
|
/**
|
||||||
* The size of a chunk, in terms of the number of blocks on one axis of the cube.
|
* The size of a chunk, in terms of the number of blocks on one axis of the cube.
|
||||||
*/
|
*/
|
||||||
public static final int SIZE = 16;
|
public static final int SIZE = 4;
|
||||||
public static final int TOTAL_SIZE = SIZE * SIZE * SIZE;
|
public static final int TOTAL_SIZE = SIZE * SIZE * SIZE;
|
||||||
|
|
||||||
private final byte[] blocks = new byte[TOTAL_SIZE];
|
private final byte[] blocks = new byte[TOTAL_SIZE];
|
||||||
|
@ -35,9 +35,37 @@ public class Chunk {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given 3D coordinate to a 1D index which points to the block
|
||||||
|
* with that coordinate within the chunk.
|
||||||
|
* @param x The x coordinate.
|
||||||
|
* @param y The y coordinate.
|
||||||
|
* @param z The z coordinate.
|
||||||
|
* @return The 1D index, or -1 if out of bounds.
|
||||||
|
*/
|
||||||
|
public static int xyzToIdx(int x, int y, int z) {
|
||||||
|
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE || z < 0 || z >= SIZE) return -1;
|
||||||
|
return x * SIZE * SIZE + y * SIZE + z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given 1D index to a 3D coordinate that points to the block
|
||||||
|
* with that index.
|
||||||
|
* @param idx The index.
|
||||||
|
* @return The 3D coordinate, or -1, -1, -1 if the index is out of bounds.
|
||||||
|
*/
|
||||||
|
public static Vector3i idxToXyz(int idx) {
|
||||||
|
if (idx < 0 || idx >= TOTAL_SIZE) return new Vector3i(-1, -1, -1);
|
||||||
|
int x = idx / (SIZE * SIZE);
|
||||||
|
int remainder = idx % (SIZE * SIZE);
|
||||||
|
int y = remainder / SIZE;
|
||||||
|
int z = remainder % SIZE;
|
||||||
|
return new Vector3i(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
public byte getBlockAt(int x, int y, int z) {
|
public byte getBlockAt(int x, int y, int z) {
|
||||||
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE || z < 0 || z >= SIZE) return 0;
|
int idx = xyzToIdx(x, y, z);
|
||||||
int idx = x * SIZE * SIZE + y * SIZE + z;
|
if (idx < 0) return 0;
|
||||||
return blocks[idx];
|
return blocks[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +74,8 @@ public class Chunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlockAt(int x, int y, int z, byte value) {
|
public void setBlockAt(int x, int y, int z, byte value) {
|
||||||
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE || z < 0 || z >= SIZE) return;
|
int idx = xyzToIdx(x, y, z);
|
||||||
int idx = x * SIZE * SIZE + y * SIZE + z;
|
if (idx < 0) return;
|
||||||
blocks[idx] = value;
|
blocks[idx] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package nl.andrewl.aos_core.model;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class ChunkTest {
|
||||||
|
@Test
|
||||||
|
public void testCoordinateIndexConversion() {
|
||||||
|
assertEquals(0, Chunk.xyzToIdx(0, 0, 0));
|
||||||
|
assertEquals(-1, Chunk.xyzToIdx(-1, 0, 0));
|
||||||
|
assertEquals(-1, Chunk.xyzToIdx(Chunk.SIZE, 0, 0));
|
||||||
|
assertEquals(1, Chunk.xyzToIdx(0, 0, 1));
|
||||||
|
assertEquals(Chunk.SIZE, Chunk.xyzToIdx(0, 1, 0));
|
||||||
|
assertEquals(Chunk.SIZE * Chunk.SIZE, Chunk.xyzToIdx(1, 0, 0));
|
||||||
|
assertEquals(Chunk.SIZE * Chunk.SIZE + 1, Chunk.xyzToIdx(1, 0, 1));
|
||||||
|
assertEquals(Chunk.TOTAL_SIZE - 1, Chunk.xyzToIdx(Chunk.SIZE - 1, Chunk.SIZE - 1, Chunk.SIZE - 1));
|
||||||
|
for (int x = 0; x < Chunk.SIZE; x++) {
|
||||||
|
for (int y = 0; y < Chunk.SIZE; y++) {
|
||||||
|
for (int z = 0; z < Chunk.SIZE; z++) {
|
||||||
|
int idx = x * Chunk.SIZE * Chunk.SIZE + y * Chunk.SIZE + z;
|
||||||
|
assertEquals(idx, Chunk.xyzToIdx(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(new Vector3i(0, 0, 0), Chunk.idxToXyz(0));
|
||||||
|
assertEquals(new Vector3i(0, 0, 2), Chunk.idxToXyz(2));
|
||||||
|
assertEquals(new Vector3i(1, 1, 1), Chunk.idxToXyz(Chunk.SIZE * Chunk.SIZE + Chunk.SIZE + 1));
|
||||||
|
assertEquals(new Vector3i(Chunk.SIZE - 1, Chunk.SIZE - 1, Chunk.SIZE - 1), Chunk.idxToXyz(Chunk.TOTAL_SIZE - 1));
|
||||||
|
assertEquals(new Vector3i(-1, -1, -1), Chunk.idxToXyz(Chunk.TOTAL_SIZE));
|
||||||
|
|
||||||
|
for (int x = 0; x < Chunk.SIZE; x++) {
|
||||||
|
for (int y = 0; y < Chunk.SIZE; y++) {
|
||||||
|
for (int z = 0; z < Chunk.SIZE; z++) {
|
||||||
|
int idx = x * Chunk.SIZE * Chunk.SIZE + y * Chunk.SIZE + z;
|
||||||
|
assertEquals(new Vector3i(x, y, z), Chunk.idxToXyz(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBlockAt() {
|
||||||
|
Chunk chunk = Chunk.random(new Vector3i(0, 0, 0), new Random(1));
|
||||||
|
for (int i = 0; i < Chunk.TOTAL_SIZE; i++) {
|
||||||
|
assertTrue(chunk.getBlockAt(Chunk.idxToXyz(i)) > 0);
|
||||||
|
}
|
||||||
|
assertEquals(0, chunk.getBlockAt(-1, 0, 0));
|
||||||
|
assertEquals(0, chunk.getBlockAt(16, 0, 5));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,267 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
sodipodi:docname="block_rendering.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.98994949"
|
||||||
|
inkscape:cx="587.56814"
|
||||||
|
inkscape:cy="738.24207"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1009"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#4f4f4f;stroke-width:1.05833327;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:3.17499981, 3.17499981000000009;stroke-dashoffset:0"
|
||||||
|
d="m 76.305449,108.17408 38.032351,0.40479 0.18719,-33.546215"
|
||||||
|
id="path912"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<g
|
||||||
|
id="g837" />
|
||||||
|
<g
|
||||||
|
id="g846"
|
||||||
|
style="stroke-width:2.11666667;stroke-miterlimit:4;stroke-dasharray:none;stroke:#000000;stroke-opacity:1;fill:none;fill-opacity:1;stroke-linejoin:round"
|
||||||
|
transform="translate(2.5390605,-2.80633)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2.11666667;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 73.766388,77.838987 v 33.141423 l 27.472262,23.78699 h 38.54331 V 90.400655 h -38.48681 z"
|
||||||
|
id="path831"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2.11666667;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="m 73.766388,77.838987 h 38.219542 l 27.79603,12.561668"
|
||||||
|
id="path833"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path839"
|
||||||
|
d="m 101.29515,90.400655 -0.0565,44.366745"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2.11666667;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#27bf00;stroke-width:2.11666667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="M 99.785711,179.07143 V 45.834821"
|
||||||
|
id="path850"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="109.31324"
|
||||||
|
y="46.033909"
|
||||||
|
id="text854"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan852"
|
||||||
|
x="109.31324"
|
||||||
|
y="46.033909"
|
||||||
|
style="stroke-width:0.26458332">+Y</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="109.58051"
|
||||||
|
y="182.60864"
|
||||||
|
id="text858"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan856"
|
||||||
|
x="109.58051"
|
||||||
|
y="182.60864"
|
||||||
|
style="stroke-width:0.26458332">-Y</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ea3400;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 19.243406,136.63829 H 192.70133"
|
||||||
|
id="path860"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="180.40692"
|
||||||
|
y="149.73448"
|
||||||
|
id="text864"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan862"
|
||||||
|
x="180.40692"
|
||||||
|
y="149.73448"
|
||||||
|
style="stroke-width:0.26458332">+Z</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="18.708866"
|
||||||
|
y="147.32906"
|
||||||
|
id="text868"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan866"
|
||||||
|
x="18.708866"
|
||||||
|
y="147.32906"
|
||||||
|
style="stroke-width:0.26458332">-Z</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#0019dc;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 44.634011,87.995228 158.49082,189.02311"
|
||||||
|
id="path870"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="164.63803"
|
||||||
|
y="193.03215"
|
||||||
|
id="text874"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan872"
|
||||||
|
x="164.63803"
|
||||||
|
y="193.03215"
|
||||||
|
style="stroke-width:0.26458332">-X</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="39.555889"
|
||||||
|
y="78.373528"
|
||||||
|
id="text878"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan876"
|
||||||
|
x="39.555889"
|
||||||
|
y="78.373528"
|
||||||
|
style="stroke-width:0.26458332">+X</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="133.42558"
|
||||||
|
y="96.483635"
|
||||||
|
id="text882"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan880"
|
||||||
|
x="133.42558"
|
||||||
|
y="96.483635"
|
||||||
|
style="stroke-width:0.26458332">a</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="106.77827"
|
||||||
|
y="97.617554"
|
||||||
|
id="text886"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan884"
|
||||||
|
x="106.77827"
|
||||||
|
y="97.617554"
|
||||||
|
style="stroke-width:0.26458332">b</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="108.66816"
|
||||||
|
y="126.72173"
|
||||||
|
id="text890"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan888"
|
||||||
|
x="108.66816"
|
||||||
|
y="126.72173"
|
||||||
|
style="stroke-width:0.26458332">c</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||||
|
x="134.55952"
|
||||||
|
y="127.85565"
|
||||||
|
id="text894"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan892"
|
||||||
|
x="134.55952"
|
||||||
|
y="127.85565"
|
||||||
|
style="stroke-width:0.26458332">d</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:5.73591566px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1433979"
|
||||||
|
x="78.88652"
|
||||||
|
y="83.134109"
|
||||||
|
id="text898"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan896"
|
||||||
|
x="78.88652"
|
||||||
|
y="83.134109"
|
||||||
|
style="stroke-width:0.1433979">e</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:6.24058294px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.15601456"
|
||||||
|
x="107.44491"
|
||||||
|
y="82.687492"
|
||||||
|
id="text902"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan900"
|
||||||
|
x="107.44491"
|
||||||
|
y="82.687492"
|
||||||
|
style="stroke-width:0.15601456">f</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:6.33006239px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.15825155"
|
||||||
|
x="108.33587"
|
||||||
|
y="105.30584"
|
||||||
|
id="text906"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan904"
|
||||||
|
x="108.33587"
|
||||||
|
y="105.30584"
|
||||||
|
style="stroke-width:0.15825155">g</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:6.04439497px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.15110987"
|
||||||
|
x="79.220268"
|
||||||
|
y="106.68898"
|
||||||
|
id="text910"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan908"
|
||||||
|
x="79.220268"
|
||||||
|
y="106.68898"
|
||||||
|
style="stroke-width:0.15110987">h</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot914"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
transform="scale(0.26458333)"><flowRegion
|
||||||
|
id="flowRegion916"><rect
|
||||||
|
id="rect918"
|
||||||
|
width="345.71429"
|
||||||
|
height="110.71429"
|
||||||
|
x="33.57143"
|
||||||
|
y="19.66254" /></flowRegion><flowPara
|
||||||
|
id="flowPara920">Block rendering schema</flowPara></flowRoot> </g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in New Issue