Added erroneous but somewhat working example.
This commit is contained in:
parent
969576b34d
commit
d34a4aa017
|
@ -212,4 +212,31 @@
|
|||
</dependency>
|
||||
|
||||
</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>
|
|
@ -1,5 +1,7 @@
|
|||
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 org.joml.Vector3i;
|
||||
import org.lwjgl.Version;
|
||||
|
@ -19,29 +21,28 @@ public class Aos2Client {
|
|||
long windowHandle = initUI();
|
||||
|
||||
Camera cam = new Camera();
|
||||
cam.setOrientationDegrees(90, 90);
|
||||
cam.setPosition(-3, 3, 0);
|
||||
glfwSetCursorPosCallback(windowHandle, cam);
|
||||
|
||||
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 chunk3 = Chunk.random(new Vector3i(1, 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(chunk3));
|
||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk4));
|
||||
chunkRenderer.addChunkMesh(new ChunkMesh(chunk));
|
||||
|
||||
while (!glfwWindowShouldClose(windowHandle)) {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
@ -94,7 +95,7 @@ public class Aos2Client {
|
|||
glfwShowWindow(windowHandle);
|
||||
|
||||
GL.createCapabilities();
|
||||
GLUtil.setupDebugMessageCallback(System.out);
|
||||
// GLUtil.setupDebugMessageCallback(System.out);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
|
|
@ -8,6 +8,9 @@ import org.lwjgl.glfw.GLFWCursorPosCallbackI;
|
|||
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
|
||||
|
||||
/**
|
||||
* Represents the player camera in the game world.
|
||||
*/
|
||||
public class Camera implements GLFWCursorPosCallbackI {
|
||||
public static final Vector3f UP = 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 BACKWARD = new Vector3f(0, 0, 1);
|
||||
|
||||
/**
|
||||
* The x, y, and z position of the camera in the world.
|
||||
*/
|
||||
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 Matrix4f viewTransform;
|
||||
private final float[] viewTransformData = new float[16];
|
||||
|
@ -50,7 +69,10 @@ public class Camera implements GLFWCursorPosCallbackI {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -60,7 +82,7 @@ public class Camera implements GLFWCursorPosCallbackI {
|
|||
|
||||
private void updateViewTransform() {
|
||||
viewTransform.identity();
|
||||
viewTransform.rotate(-orientation.y, RIGHT);
|
||||
viewTransform.rotate(-orientation.y + ((float) Math.PI / 2), RIGHT);
|
||||
viewTransform.rotate(-orientation.x, UP);
|
||||
viewTransform.translate(-position.x, -position.y, -position.z);
|
||||
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;
|
||||
|
|
@ -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.Matrix4f;
|
||||
|
||||
|
@ -14,6 +16,7 @@ public class ChunkRenderer {
|
|||
private final int viewTransformUniform;
|
||||
private final int normalTransformUniform;
|
||||
private final int chunkPositionUniform;
|
||||
private final int chunkSizeUniform;
|
||||
|
||||
private final Matrix4f projectionTransform = new Matrix4f().perspective(70, 800 / 600.0f, 0.01f, 100.0f);
|
||||
|
||||
|
@ -22,16 +25,18 @@ public class ChunkRenderer {
|
|||
public ChunkRenderer() {
|
||||
this.shaderProgram = new ShaderProgram.Builder()
|
||||
.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();
|
||||
shaderProgram.use();
|
||||
this.projectionTransformUniform = shaderProgram.getUniform("projectionTransform");
|
||||
this.viewTransformUniform = shaderProgram.getUniform("viewTransform");
|
||||
this.normalTransformUniform = shaderProgram.getUniform("normalTransform");
|
||||
this.chunkPositionUniform = shaderProgram.getUniform("chunkPosition");
|
||||
this.chunkSizeUniform = shaderProgram.getUniform("chunkSize");
|
||||
|
||||
// Preemptively load projection transform, which doesn't change much.
|
||||
glUniformMatrix4fv(projectionTransformUniform, false, projectionTransform.get(new float[16]));
|
||||
glUniform1i(chunkSizeUniform, Chunk.SIZE);
|
||||
}
|
||||
|
||||
public void addChunkMesh(ChunkMesh mesh) {
|
||||
|
@ -39,13 +44,9 @@ public class ChunkRenderer {
|
|||
}
|
||||
|
||||
public void draw(Camera cam) {
|
||||
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
|
||||
Matrix3f normalTransform = new Matrix3f();
|
||||
glUniformMatrix3fv(normalTransformUniform, false, normalTransform.get(new float[9]));
|
||||
shaderProgram.use();
|
||||
|
||||
glUniformMatrix4fv(viewTransformUniform, false, cam.getViewTransformData());
|
||||
for (var mesh : chunkMeshes) {
|
||||
// For each chunk, specify its position so that the shaders can draw it offset.
|
||||
glUniform3iv(chunkPositionUniform, mesh.getPositionData());
|
||||
mesh.draw();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package nl.andrewl.aos2_client;
|
||||
package nl.andrewl.aos2_client.render;
|
||||
|
||||
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.
|
||||
*/
|
||||
public class ShaderProgram {
|
||||
/**
|
||||
* The id of the generated shader program.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
public ShaderProgram(int 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() {
|
||||
glUseProgram(id);
|
||||
}
|
||||
|
@ -53,5 +61,9 @@ public class ShaderProgram {
|
|||
glLinkProgram(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.lwjgl.BufferUtils;
|
|
@ -15,5 +15,4 @@ void main() {
|
|||
// No specular component.
|
||||
|
||||
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 viewTransform;
|
||||
uniform mat3 normalTransform;
|
||||
uniform ivec3 chunkPosition;
|
||||
uniform int chunkSize;
|
||||
|
||||
out vec3 vertexPosition;
|
||||
out vec3 vertexColor;
|
||||
out vec3 vertexNormal;
|
||||
|
||||
void main() {
|
||||
vec3 realVertexPosition = vertexPositionIn + (chunkPosition * 16);
|
||||
vertexPosition = vertexPositionIn + (chunkPosition * chunkSize);
|
||||
|
||||
gl_Position = projectionTransform * viewTransform * vec4(realVertexPosition, 1.0);
|
||||
vertexPosition = realVertexPosition;
|
||||
gl_Position = projectionTransform * viewTransform * vec4(vertexPosition, 1.0);
|
||||
vertexColor = vertexColorIn;
|
||||
vertexNormal = normalize(normalTransform * vertexNormalIn);
|
||||
vertexNormal = vertexNormalIn;
|
||||
}
|
||||
|
|
15
core/pom.xml
15
core/pom.xml
|
@ -23,5 +23,20 @@
|
|||
<artifactId>joml</artifactId>
|
||||
<version>1.10.4</version>
|
||||
</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>
|
||||
</project>
|
|
@ -6,4 +6,15 @@ public class MathUtils {
|
|||
final double offsetValue = value - 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.
|
||||
*/
|
||||
public static final int SIZE = 16;
|
||||
public static final int SIZE = 4;
|
||||
public static final int TOTAL_SIZE = SIZE * SIZE * SIZE;
|
||||
|
||||
private final byte[] blocks = new byte[TOTAL_SIZE];
|
||||
|
@ -35,9 +35,37 @@ public class Chunk {
|
|||
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) {
|
||||
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE || z < 0 || z >= SIZE) return 0;
|
||||
int idx = x * SIZE * SIZE + y * SIZE + z;
|
||||
int idx = xyzToIdx(x, y, z);
|
||||
if (idx < 0) return 0;
|
||||
return blocks[idx];
|
||||
}
|
||||
|
||||
|
@ -46,8 +74,8 @@ public class Chunk {
|
|||
}
|
||||
|
||||
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 = x * SIZE * SIZE + y * SIZE + z;
|
||||
int idx = xyzToIdx(x, y, z);
|
||||
if (idx < 0) return;
|
||||
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