diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java index 79ebb18..d5e8c0a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java @@ -24,6 +24,7 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.common.block.BlockFace; +import ru.windcorp.progressia.common.util.Vectors; public class Faces { @@ -40,40 +41,47 @@ public class Faces { ) { VertexBuilder builder = program.getVertexBuilder(); - Vec3 pos = new Vec3(); - Vec2 texCoords = new Vec2(); + Vec3 pos = Vectors.grab3(); + Vec2 texCoords = Vectors.grab2(); - builder.addVertex( - origin, - colorMultiplier, - texCoords.set(0, 0) - ).addVertex( - pos.set(origin).add(height), - colorMultiplier, - texCoords.set(0, 1) - ).addVertex( - pos.set(origin).add(width), - colorMultiplier, - texCoords.set(1, 0) - ).addVertex( - pos.add(height), - colorMultiplier, - texCoords.set(1, 1) - ); + try { - ShortBuffer buffer = flip ? ShortBuffer.wrap(new short[] { - 0, 1, 3, - 0, 3, 2 - }) : ShortBuffer.wrap(new short[] { - 3, 1, 0, - 2, 3, 0 - }); + builder.addVertex( + origin, + colorMultiplier, + texCoords.set(0, 0) + ).addVertex( + pos.set(origin).add(height), + colorMultiplier, + texCoords.set(0, 1) + ).addVertex( + pos.set(origin).add(width), + colorMultiplier, + texCoords.set(1, 0) + ).addVertex( + pos.add(height), + colorMultiplier, + texCoords.set(1, 1) + ); + + ShortBuffer buffer = flip ? ShortBuffer.wrap(new short[] { + 0, 1, 3, + 0, 3, 2 + }) : ShortBuffer.wrap(new short[] { + 3, 1, 0, + 2, 3, 0 + }); + + return new Face( + texture, + builder.assemble(), + buffer + ); - return new Face( - texture, - builder.assemble(), - buffer - ); + } finally { + Vectors.release(pos); + Vectors.release(texCoords); + } } public static Face createBlockFace( @@ -86,15 +94,22 @@ public class Faces { ) { BlockFaceVectors vectors = BlockFaceVectors.get(inner); - Vec3 origin = new Vec3(blockCenter).add(vectors.getOrigin(face)); - Vec3 width = vectors.getWidth(face); - Vec3 height = vectors.getHeight(face); - - return createRectangle( - program, texture, colorMultiplier, - origin, width, height, - inner - ); + Vec3 origin = + Vectors.grab3().set(blockCenter).add(vectors.getOrigin(face)); + try { + + Vec3 width = vectors.getWidth(face); + Vec3 height = vectors.getHeight(face); + + return createRectangle( + program, texture, colorMultiplier, + origin, width, height, + inner + ); + + } finally { + Vectors.release(origin); + } } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java index 4fb9bdd..fabc468 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.client.graphics.model; import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.backend.Usage; import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.util.Vectors; public class Shapes { @@ -42,8 +43,8 @@ public class Shapes { Texture westTexture ) { - Vec3 faceOrigin = new Vec3(); - Vec3 faceWidth = new Vec3(); + Vec3 faceOrigin = Vectors.grab3(); + Vec3 faceWidth = Vectors.grab3(); Face top = Faces.createRectangle( program, @@ -105,6 +106,9 @@ public class Shapes { top, bottom, north, south, east, west ); + Vectors.release(faceOrigin); + Vectors.release(faceWidth); + return result; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 1b7ebf9..95d02c9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -21,6 +21,7 @@ import org.lwjgl.glfw.GLFW; import glm.mat._3.Mat3; import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.Layer; import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; @@ -29,8 +30,9 @@ import ru.windcorp.progressia.client.graphics.input.InputEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.bus.Input; import ru.windcorp.progressia.client.world.WorldRender; -import ru.windcorp.progressia.common.block.BlockData; import ru.windcorp.progressia.common.block.BlockDataRegistry; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.WorldData; public class LayerWorld extends Layer { @@ -44,7 +46,6 @@ public class LayerWorld extends Layer { ); private final Vec3 velocity = new Vec3(); - private final Vec3 tmp = new Vec3(); private final Mat3 angMat = new Mat3(); @@ -52,9 +53,6 @@ public class LayerWorld extends Layer { private int movementRight = 0; private int movementUp = 0; - private static final boolean I_WANT_TO_THROW_UP = false; - private float shakeParam = 0; - private final WorldRenderHelper helper = new WorldRenderHelper(); private final WorldRender world = new WorldRender(new WorldData()); @@ -82,31 +80,26 @@ public class LayerWorld extends Layer { helper.reset(); angMat.set().rotateZ(-camera.getYaw()); - - tmp.set(movementForward, -movementRight, 0); - if (movementForward != 0 && movementRight != 0) tmp.normalize(); - angMat.mul_(tmp); // bug in jglm - tmp.z = movementUp; - tmp.mul(0.1f); - tmp.sub(velocity); - tmp.mul(0.1f); - velocity.add(tmp); - tmp.set(velocity); - tmp.mul((float) (GraphicsInterface.getFrameLength() * 60)); - camera.move(tmp); - if (I_WANT_TO_THROW_UP) { - shakeParam += tmp.set(tmp.x, 0, tmp.z).length() * 1.5f; - float vel = tmp.set(velocity).set(tmp.x, 0, tmp.z).length() * 0.7f; - - helper.pushViewTransform().translate( - (float) Math.sin(shakeParam) * vel, - (float) Math.sin(2 * shakeParam) * vel, - 0.25f - ).rotateZ( - (float) Math.sin(shakeParam) * vel * 0.15f - ); - } + Vec3 movement = Vectors.grab3(); + + movement.set(movementForward, -movementRight, 0); + if (movementForward != 0 && movementRight != 0) movement.normalize(); + angMat.mul_(movement); // bug in jglm + movement.z = movementUp; + movement.mul(0.1f); + movement.sub(velocity); + movement.mul(0.1f); + velocity.add(movement); + + Vectors.release(movement); + + Vec3 velCopy = Vectors.grab3().set(velocity); + + velCopy.mul((float) (GraphicsInterface.getFrameLength() * 60)); + camera.move(velCopy); + + Vectors.release(velCopy); } private void renderWorld() { @@ -174,13 +167,19 @@ public class LayerWorld extends Layer { case GLFW.GLFW_KEY_G: if (!event.isPress()) return; - BlockData[][][] data = world.getData().getChunk(0, 0, 0).tmp_getBlocks(); - if (data[0][0][0].getId().equals("Test:Stone")) { - data[0][0][0] = BlockDataRegistry.get("Test:Glass"); + Vec3i pos = Vectors.grab3i().set(0, 0, 0); + Vec3i chunkPos = Vectors.grab3i().set(0, 0, 0); + + ChunkData chunk = world.getData().getChunk(chunkPos); + if (chunk.getBlock(pos).getId().equals("Test:Stone")) { + chunk.setBlock(pos, BlockDataRegistry.get("Test:Glass")); } else { - data[0][0][0] = BlockDataRegistry.get("Test:Stone"); + chunk.setBlock(pos, BlockDataRegistry.get("Test:Stone")); } - world.getChunk(0, 0, 0).markForUpdate(); + world.getChunk(chunkPos).markForUpdate(); + + Vectors.release(pos); + Vectors.release(chunkPos); break; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 0a60faf..1495f8e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.stream.Collectors; import glm.mat._4.Mat4; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Model; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; @@ -64,10 +65,8 @@ public class ChunkRender { return needsUpdate; } - public BlockRender getBlock(int xInChunk, int yInChunk, int zInChunk) { - return BlockRenders.get( - getData().getBlock(xInChunk, yInChunk, zInChunk).getId() - ); + public BlockRender getBlock(Vec3i posInChunk) { + return BlockRenders.get(getData().getBlock(posInChunk).getId()); } public void render(ShapeRenderHelper renderer) { @@ -96,11 +95,13 @@ public class ChunkRender { StaticModel.Builder builder = StaticModel.builder(); + Vec3i cursor = new Vec3i(); for (int x = 0; x < ChunkData.BLOCKS_PER_CHUNK; ++x) { for (int y = 0; y < ChunkData.BLOCKS_PER_CHUNK; ++y) { for (int z = 0; z < ChunkData.BLOCKS_PER_CHUNK; ++z) { + cursor.set(x, y, z); - BlockRender block = getBlock(x, y, z); + BlockRender block = getBlock(cursor); if (block instanceof BlockRenderNone) { continue; diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index c441169..249dd91 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.WorldData; @@ -47,8 +48,8 @@ public class WorldRender { return chunks.get(chunkData); } - public ChunkRender getChunk(int x, int y, int z) { - return chunks.get(getData().getChunk(x, y, z)); + public ChunkRender getChunk(Vec3i pos) { + return chunks.get(getData().getChunk(pos)); } public Collection getChunks() { diff --git a/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java new file mode 100644 index 0000000..fbd65c0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java @@ -0,0 +1,33 @@ +package ru.windcorp.progressia.common.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class LowOverheadCache { + + private final ThreadLocal> ready = + ThreadLocal.withInitial(ArrayList::new); + + private final Supplier generator; + + public LowOverheadCache(Supplier generator) { + this.generator = generator; + } + + public E grab() { + List list = ready.get(); + int size = list.size(); + + if (size == 0) { + return generator.get(); + } + + return list.remove(size - 1); + } + + public void release(E object) { + ready.get().add(object); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java new file mode 100644 index 0000000..2468707 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java @@ -0,0 +1,99 @@ +package ru.windcorp.progressia.common.util; + +import glm.vec._2.Vec2; +import glm.vec._2.i.Vec2i; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import glm.vec._4.Vec4; +import glm.vec._4.i.Vec4i; + +/** + * A set of caches for GLM vector objects. Use this instead of allocating new + * vectors when the objects are effectively local. + *

+ * All {@code grab}bed objects must be {@code release}d as soon as possible. + * Ideally, user code should be: + *

+ * Vec3 myVector = Vectors.grab3();
+ * try {
+ *     // use myVector
+ * } finally {
+ *     Vectors.release(myVector);
+ * }
+ * 
+ * Provided objects may be reused after {@code release} has been invoked; + * do not store them. + *

+ * This class is thread- and recursion-safe. + */ +public class Vectors { + + private static final LowOverheadCache VEC3IS = + new LowOverheadCache<>(Vec3i::new); + + public static Vec3i grab3i() { + return VEC3IS.grab(); + } + + public static void release(Vec3i v) { + VEC3IS.release(v); + } + + private static final LowOverheadCache VEC3S = + new LowOverheadCache<>(Vec3::new); + + public static Vec3 grab3() { + return VEC3S.grab(); + } + + public static void release(Vec3 v) { + VEC3S.release(v); + } + + private static final LowOverheadCache VEC2IS = + new LowOverheadCache<>(Vec2i::new); + + public static Vec2i grab2i() { + return VEC2IS.grab(); + } + + public static void release(Vec2i v) { + VEC2IS.release(v); + } + + private static final LowOverheadCache VEC2S = + new LowOverheadCache<>(Vec2::new); + + public static Vec2 grab2() { + return VEC2S.grab(); + } + + public static void release(Vec2 v) { + VEC2S.release(v); + } + + private static final LowOverheadCache VEC4IS = + new LowOverheadCache<>(Vec4i::new); + + public static Vec4i grab4i() { + return VEC4IS.grab(); + } + + public static void release(Vec4i v) { + VEC4IS.release(v); + } + + private static final LowOverheadCache VEC4S = + new LowOverheadCache<>(Vec4::new); + + public static Vec4 grab4() { + return VEC4S.grab(); + } + + public static void release(Vec4 v) { + VEC4S.release(v); + } + + private Vectors() {} + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index e6f05b1..33e9e8e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -24,14 +24,13 @@ import ru.windcorp.progressia.common.block.BlockDataRegistry; public class ChunkData { public static final int BLOCKS_PER_CHUNK = 16; + public static final int TILES_PER_FACE = 8; - private final int x; - private final int y; - private final int z; + private final Vec3i position = new Vec3i(); - private final BlockData[][][] blocks = new BlockData[BLOCKS_PER_CHUNK] - [BLOCKS_PER_CHUNK] - [BLOCKS_PER_CHUNK]; + private final BlockData[] blocks = new BlockData[ + BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + ]; private final BlockData grass = BlockDataRegistry.get("Test:Grass"); private final BlockData dirt = BlockDataRegistry.get("Test:Dirt"); @@ -39,17 +38,11 @@ public class ChunkData { private final BlockData air = BlockDataRegistry.get("Test:Air"); public ChunkData(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; + this.position.set(x, y, z); tmp_generate(); } - public BlockData[][][] tmp_getBlocks() { - return blocks; - } - private void tmp_generate() { Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2); Vec3i pos = new Vec3i(); @@ -59,15 +52,15 @@ public class ChunkData { for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) { pos.set(x, y, z); - float f = aPoint.sub(pos, pos).length(); + pos.set(x, y, z); if (f > 17) { - blocks[x][y][z] = stone; + setBlock(pos, stone); } else if (f > 14) { - blocks[x][y][z] = dirt; + setBlock(pos, dirt); } else { - blocks[x][y][z] = air; + setBlock(pos, air); } } @@ -76,42 +69,69 @@ public class ChunkData { for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) { for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) { - int z; - for (z = BLOCKS_PER_CHUNK - 1; z >= 0 && blocks[x][y][z] == air; --z); + pos.set(x, y, 0); - blocks[x][y][z] = grass; + for (pos.z = BLOCKS_PER_CHUNK - 1; pos.z >= 0 && getBlock(pos) == air; --pos.z); + + setBlock(pos, grass); } } } - public BlockData getBlock(int xInChunk, int yInChunk, int zInChunk) { - if (!isInBounds(xInChunk, yInChunk, zInChunk)) { + public BlockData getBlock(Vec3i posInChunk) { + if (!isInBounds(posInChunk)) { throw new IllegalArgumentException( - "Coordinates (" + x + "; " + y + "; " + z + ") " + "Coordinates " + str(posInChunk) + " " + "are not legal chunk coordinates" ); } - return blocks[xInChunk][yInChunk][zInChunk]; + return blocks[getBlockIndex(posInChunk)]; + } + + public void setBlock(Vec3i posInChunk, BlockData block) { + if (!isInBounds(posInChunk)) { + throw new IllegalArgumentException( + "Coordinates " + str(posInChunk) + " " + + "are not legal chunk coordinates" + ); + } + + blocks[getBlockIndex(posInChunk)] = block; } - private boolean isInBounds(int xInChunk, int yInChunk, int zInChunk) { + private boolean isInBounds(Vec3i posInChunk) { return - xInChunk >= 0 && xInChunk < BLOCKS_PER_CHUNK || - yInChunk >= 0 && yInChunk < BLOCKS_PER_CHUNK || - zInChunk >= 0 && zInChunk < BLOCKS_PER_CHUNK; + posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && + posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && + posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; + } + + private int getBlockIndex(Vec3i posInChunk) { + return + posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + + posInChunk.y * BLOCKS_PER_CHUNK + + posInChunk.x; } public int getX() { - return x; + return position.x; } public int getY() { - return y; + return position.y; } public int getZ() { - return z; + return position.z; + } + + public Vec3i getPosition() { + return position; + } + + private static String str(Vec3i v) { + return "(" + v.x + "; " + v.y + "; " + v.z + ")"; } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 87af3ba..cff9cc4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.common.world; import java.util.Collection; import java.util.Collections; +import glm.vec._3.i.Vec3i; import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TLongObjectHashMap; import ru.windcorp.progressia.common.util.CoordinatePacker; @@ -38,8 +39,8 @@ public class WorldData { } } - public ChunkData getChunk(int x, int y, int z) { - long key = CoordinatePacker.pack3IntsIntoLong(x, y, z); + public ChunkData getChunk(Vec3i pos) { + long key = CoordinatePacker.pack3IntsIntoLong(pos.x, pos.y, pos.z); return chunks.get(key); }