Created fast Vec caches and increased the use of Vecs in code

This commit is contained in:
OLEGSHA 2020-08-26 20:58:38 +03:00
parent 65eaae68a8
commit 21a30e8b97
9 changed files with 289 additions and 116 deletions

View File

@ -24,6 +24,7 @@ import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.block.BlockFace; import ru.windcorp.progressia.common.block.BlockFace;
import ru.windcorp.progressia.common.util.Vectors;
public class Faces { public class Faces {
@ -40,40 +41,47 @@ public class Faces {
) { ) {
VertexBuilder builder = program.getVertexBuilder(); VertexBuilder builder = program.getVertexBuilder();
Vec3 pos = new Vec3(); Vec3 pos = Vectors.grab3();
Vec2 texCoords = new Vec2(); Vec2 texCoords = Vectors.grab2();
builder.addVertex( try {
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[] { builder.addVertex(
0, 1, 3, origin,
0, 3, 2 colorMultiplier,
}) : ShortBuffer.wrap(new short[] { texCoords.set(0, 0)
3, 1, 0, ).addVertex(
2, 3, 0 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( } finally {
texture, Vectors.release(pos);
builder.assemble(), Vectors.release(texCoords);
buffer }
);
} }
public static Face createBlockFace( public static Face createBlockFace(
@ -86,15 +94,22 @@ public class Faces {
) { ) {
BlockFaceVectors vectors = BlockFaceVectors.get(inner); BlockFaceVectors vectors = BlockFaceVectors.get(inner);
Vec3 origin = new Vec3(blockCenter).add(vectors.getOrigin(face)); Vec3 origin =
Vec3 width = vectors.getWidth(face); Vectors.grab3().set(blockCenter).add(vectors.getOrigin(face));
Vec3 height = vectors.getHeight(face); try {
return createRectangle( Vec3 width = vectors.getWidth(face);
program, texture, colorMultiplier, Vec3 height = vectors.getHeight(face);
origin, width, height,
inner return createRectangle(
); program, texture, colorMultiplier,
origin, width, height,
inner
);
} finally {
Vectors.release(origin);
}
} }
} }

View File

@ -20,6 +20,7 @@ package ru.windcorp.progressia.client.graphics.model;
import glm.vec._3.Vec3; import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.graphics.backend.Usage; import ru.windcorp.progressia.client.graphics.backend.Usage;
import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.util.Vectors;
public class Shapes { public class Shapes {
@ -42,8 +43,8 @@ public class Shapes {
Texture westTexture Texture westTexture
) { ) {
Vec3 faceOrigin = new Vec3(); Vec3 faceOrigin = Vectors.grab3();
Vec3 faceWidth = new Vec3(); Vec3 faceWidth = Vectors.grab3();
Face top = Faces.createRectangle( Face top = Faces.createRectangle(
program, program,
@ -105,6 +106,9 @@ public class Shapes {
top, bottom, north, south, east, west top, bottom, north, south, east, west
); );
Vectors.release(faceOrigin);
Vectors.release(faceWidth);
return result; return result;
} }

View File

@ -21,6 +21,7 @@ import org.lwjgl.glfw.GLFW;
import glm.mat._3.Mat3; import glm.mat._3.Mat3;
import glm.vec._3.Vec3; import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.Layer; import ru.windcorp.progressia.client.graphics.Layer;
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; 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.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input; import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.client.world.WorldRender; 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.block.BlockDataRegistry;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldData;
public class LayerWorld extends Layer { public class LayerWorld extends Layer {
@ -44,7 +46,6 @@ public class LayerWorld extends Layer {
); );
private final Vec3 velocity = new Vec3(); private final Vec3 velocity = new Vec3();
private final Vec3 tmp = new Vec3();
private final Mat3 angMat = new Mat3(); private final Mat3 angMat = new Mat3();
@ -52,9 +53,6 @@ public class LayerWorld extends Layer {
private int movementRight = 0; private int movementRight = 0;
private int movementUp = 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 WorldRenderHelper helper = new WorldRenderHelper();
private final WorldRender world = new WorldRender(new WorldData()); private final WorldRender world = new WorldRender(new WorldData());
@ -82,31 +80,26 @@ public class LayerWorld extends Layer {
helper.reset(); helper.reset();
angMat.set().rotateZ(-camera.getYaw()); 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) { Vec3 movement = Vectors.grab3();
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; movement.set(movementForward, -movementRight, 0);
if (movementForward != 0 && movementRight != 0) movement.normalize();
helper.pushViewTransform().translate( angMat.mul_(movement); // bug in jglm
(float) Math.sin(shakeParam) * vel, movement.z = movementUp;
(float) Math.sin(2 * shakeParam) * vel, movement.mul(0.1f);
0.25f movement.sub(velocity);
).rotateZ( movement.mul(0.1f);
(float) Math.sin(shakeParam) * vel * 0.15f 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() { private void renderWorld() {
@ -174,13 +167,19 @@ public class LayerWorld extends Layer {
case GLFW.GLFW_KEY_G: case GLFW.GLFW_KEY_G:
if (!event.isPress()) return; if (!event.isPress()) return;
BlockData[][][] data = world.getData().getChunk(0, 0, 0).tmp_getBlocks(); Vec3i pos = Vectors.grab3i().set(0, 0, 0);
if (data[0][0][0].getId().equals("Test:Stone")) { Vec3i chunkPos = Vectors.grab3i().set(0, 0, 0);
data[0][0][0] = BlockDataRegistry.get("Test:Glass");
ChunkData chunk = world.getData().getChunk(chunkPos);
if (chunk.getBlock(pos).getId().equals("Test:Stone")) {
chunk.setBlock(pos, BlockDataRegistry.get("Test:Glass"));
} else { } 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; break;
} }

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import glm.mat._4.Mat4; 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.Model;
import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.Shape;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
@ -64,10 +65,8 @@ public class ChunkRender {
return needsUpdate; return needsUpdate;
} }
public BlockRender getBlock(int xInChunk, int yInChunk, int zInChunk) { public BlockRender getBlock(Vec3i posInChunk) {
return BlockRenders.get( return BlockRenders.get(getData().getBlock(posInChunk).getId());
getData().getBlock(xInChunk, yInChunk, zInChunk).getId()
);
} }
public void render(ShapeRenderHelper renderer) { public void render(ShapeRenderHelper renderer) {
@ -96,11 +95,13 @@ public class ChunkRender {
StaticModel.Builder builder = StaticModel.builder(); StaticModel.Builder builder = StaticModel.builder();
Vec3i cursor = new Vec3i();
for (int x = 0; x < ChunkData.BLOCKS_PER_CHUNK; ++x) { for (int x = 0; x < ChunkData.BLOCKS_PER_CHUNK; ++x) {
for (int y = 0; y < ChunkData.BLOCKS_PER_CHUNK; ++y) { for (int y = 0; y < ChunkData.BLOCKS_PER_CHUNK; ++y) {
for (int z = 0; z < ChunkData.BLOCKS_PER_CHUNK; ++z) { 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) { if (block instanceof BlockRenderNone) {
continue; continue;

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldData;
@ -47,8 +48,8 @@ public class WorldRender {
return chunks.get(chunkData); return chunks.get(chunkData);
} }
public ChunkRender getChunk(int x, int y, int z) { public ChunkRender getChunk(Vec3i pos) {
return chunks.get(getData().getChunk(x, y, z)); return chunks.get(getData().getChunk(pos));
} }
public Collection<ChunkRender> getChunks() { public Collection<ChunkRender> getChunks() {

View File

@ -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<E> {
private final ThreadLocal<List<E>> ready =
ThreadLocal.withInitial(ArrayList::new);
private final Supplier<E> generator;
public LowOverheadCache(Supplier<E> generator) {
this.generator = generator;
}
public E grab() {
List<E> 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);
}
}

View File

@ -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.
* <p>
* All {@code grab}bed objects must be {@code release}d as soon as possible.
* Ideally, user code should be:
* <pre>
* Vec3 myVector = Vectors.grab3();
* try {
* // use myVector
* } finally {
* Vectors.release(myVector);
* }
* </pre>
* Provided objects may be reused after {@code release} has been invoked;
* do not store them.
* <p>
* This class is thread- and recursion-safe.
*/
public class Vectors {
private static final LowOverheadCache<Vec3i> 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<Vec3> 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<Vec2i> 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<Vec2> 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<Vec4i> 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<Vec4> VEC4S =
new LowOverheadCache<>(Vec4::new);
public static Vec4 grab4() {
return VEC4S.grab();
}
public static void release(Vec4 v) {
VEC4S.release(v);
}
private Vectors() {}
}

View File

@ -24,14 +24,13 @@ import ru.windcorp.progressia.common.block.BlockDataRegistry;
public class ChunkData { public class ChunkData {
public static final int BLOCKS_PER_CHUNK = 16; public static final int BLOCKS_PER_CHUNK = 16;
public static final int TILES_PER_FACE = 8;
private final int x; private final Vec3i position = new Vec3i();
private final int y;
private final int z;
private final BlockData[][][] blocks = new BlockData[BLOCKS_PER_CHUNK] private final BlockData[] blocks = new BlockData[
[BLOCKS_PER_CHUNK] BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK
[BLOCKS_PER_CHUNK]; ];
private final BlockData grass = BlockDataRegistry.get("Test:Grass"); private final BlockData grass = BlockDataRegistry.get("Test:Grass");
private final BlockData dirt = BlockDataRegistry.get("Test:Dirt"); private final BlockData dirt = BlockDataRegistry.get("Test:Dirt");
@ -39,17 +38,11 @@ public class ChunkData {
private final BlockData air = BlockDataRegistry.get("Test:Air"); private final BlockData air = BlockDataRegistry.get("Test:Air");
public ChunkData(int x, int y, int z) { public ChunkData(int x, int y, int z) {
this.x = x; this.position.set(x, y, z);
this.y = y;
this.z = z;
tmp_generate(); tmp_generate();
} }
public BlockData[][][] tmp_getBlocks() {
return blocks;
}
private void tmp_generate() { private void tmp_generate() {
Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2); Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2);
Vec3i pos = new Vec3i(); Vec3i pos = new Vec3i();
@ -59,15 +52,15 @@ public class ChunkData {
for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) { for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) {
pos.set(x, y, z); pos.set(x, y, z);
float f = aPoint.sub(pos, pos).length(); float f = aPoint.sub(pos, pos).length();
pos.set(x, y, z);
if (f > 17) { if (f > 17) {
blocks[x][y][z] = stone; setBlock(pos, stone);
} else if (f > 14) { } else if (f > 14) {
blocks[x][y][z] = dirt; setBlock(pos, dirt);
} else { } 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 x = 0; x < BLOCKS_PER_CHUNK; ++x) {
for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) { for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) {
int z; pos.set(x, y, 0);
for (z = BLOCKS_PER_CHUNK - 1; z >= 0 && blocks[x][y][z] == air; --z);
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) { public BlockData getBlock(Vec3i posInChunk) {
if (!isInBounds(xInChunk, yInChunk, zInChunk)) { if (!isInBounds(posInChunk)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Coordinates (" + x + "; " + y + "; " + z + ") " "Coordinates " + str(posInChunk) + " "
+ "are not legal chunk coordinates" + "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 return
xInChunk >= 0 && xInChunk < BLOCKS_PER_CHUNK || posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK &&
yInChunk >= 0 && yInChunk < BLOCKS_PER_CHUNK || posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK &&
zInChunk >= 0 && zInChunk < 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() { public int getX() {
return x; return position.x;
} }
public int getY() { public int getY() {
return y; return position.y;
} }
public int getZ() { 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 + ")";
} }
} }

View File

@ -20,6 +20,7 @@ package ru.windcorp.progressia.common.world;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import glm.vec._3.i.Vec3i;
import gnu.trove.map.TLongObjectMap; import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap;
import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.util.CoordinatePacker;
@ -38,8 +39,8 @@ public class WorldData {
} }
} }
public ChunkData getChunk(int x, int y, int z) { public ChunkData getChunk(Vec3i pos) {
long key = CoordinatePacker.pack3IntsIntoLong(x, y, z); long key = CoordinatePacker.pack3IntsIntoLong(pos.x, pos.y, pos.z);
return chunks.get(key); return chunks.get(key);
} }