Optimized tile render and added CRO tile support
- CROs now support tiles - CROCube refactored - Test content: - Added sand and flower tiles - Removed grass blocks, added grass tiles
@ -19,13 +19,13 @@ package ru.windcorp.progressia.client.world;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import glm.mat._4.Mat4;
|
import glm.mat._4.Mat4;
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
import glm.vec._3.i.Vec3i;
|
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.ShapeRenderHelper;
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
import ru.windcorp.progressia.client.graphics.model.StaticModel;
|
import ru.windcorp.progressia.client.graphics.model.StaticModel;
|
||||||
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
||||||
@ -114,12 +114,10 @@ public class ChunkRender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ChunkRenderOptimizer optimizer : optimizers) {
|
optimizers.stream()
|
||||||
Shape result = optimizer.endRender();
|
.map(ChunkRenderOptimizer::endRender)
|
||||||
if (result != null) {
|
.filter(Objects::nonNull)
|
||||||
builder.addPart(result);
|
.forEach(builder::addPart);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model = new StaticModel(builder);
|
model = new StaticModel(builder);
|
||||||
needsUpdate = false;
|
needsUpdate = false;
|
||||||
@ -131,55 +129,41 @@ public class ChunkRender {
|
|||||||
Builder builder
|
Builder builder
|
||||||
) {
|
) {
|
||||||
BlockRender block = getBlock(cursor);
|
BlockRender block = getBlock(cursor);
|
||||||
int x = cursor.x;
|
|
||||||
int y = cursor.y;
|
|
||||||
int z = cursor.z;
|
|
||||||
|
|
||||||
if (block instanceof BlockRenderNone) {
|
if (block instanceof BlockRenderNone) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
forwardBlockToOptimizers(block, x, y, z, optimizers);
|
forwardBlockToOptimizers(block, cursor, optimizers);
|
||||||
|
|
||||||
if (!block.needsOwnRenderable()) {
|
if (!block.needsOwnRenderable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tryToCreateBlockRenderable(block, x, y, z, builder)) {
|
addBlockRenderable(block, cursor, builder);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addBlockRenderAsRenderable(block, x, y, z, builder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forwardBlockToOptimizers(
|
private void forwardBlockToOptimizers(
|
||||||
BlockRender block, int x, int y, int z,
|
BlockRender block, Vec3i cursor,
|
||||||
Collection<ChunkRenderOptimizer> optimizers
|
Collection<ChunkRenderOptimizer> optimizers
|
||||||
) {
|
) {
|
||||||
optimizers.forEach(bro -> bro.processBlock(block, x, y, z));
|
optimizers.forEach(cro -> cro.processBlock(block, cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryToCreateBlockRenderable(
|
private void addBlockRenderable(
|
||||||
BlockRender block, int x, int y, int z,
|
BlockRender block,
|
||||||
|
Vec3i cursor,
|
||||||
Builder builder
|
Builder builder
|
||||||
) {
|
) {
|
||||||
WorldRenderable renderable = block.createRenderable();
|
WorldRenderable renderable = block.createRenderable();
|
||||||
|
|
||||||
if (renderable == null) {
|
if (renderable == null) {
|
||||||
return false;
|
renderable = block::render;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.addPart(renderable, new Mat4().identity().translate(x, y, z));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addBlockRenderAsRenderable(
|
|
||||||
BlockRender block, int x, int y, int z,
|
|
||||||
Builder builder
|
|
||||||
) {
|
|
||||||
builder.addPart(
|
builder.addPart(
|
||||||
block::render,
|
renderable,
|
||||||
new Mat4().identity().translate(x, y, z)
|
new Mat4().identity().translate(cursor.x, cursor.y, cursor.z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,6 +214,13 @@ public class ChunkRender {
|
|||||||
|
|
||||||
Vec3 pos = Vectors.grab3().set(cursor.x, cursor.y, cursor.z);
|
Vec3 pos = Vectors.grab3().set(cursor.x, cursor.y, cursor.z);
|
||||||
|
|
||||||
|
optimizers.forEach(cro -> cro.processTile(tile, cursor, face));
|
||||||
|
|
||||||
|
if (!tile.needsOwnRenderable()) {
|
||||||
|
Vectors.release(pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Vec3 offset = Vectors.grab3().set(
|
Vec3 offset = Vectors.grab3().set(
|
||||||
face.getVector().x, face.getVector().y, face.getVector().z
|
face.getVector().x, face.getVector().y, face.getVector().z
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,6 @@ package ru.windcorp.progressia.client.world.renders;
|
|||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
||||||
import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizer;
|
|
||||||
import ru.windcorp.progressia.common.util.Namespaced;
|
import ru.windcorp.progressia.common.util.Namespaced;
|
||||||
|
|
||||||
public abstract class BlockRender extends Namespaced {
|
public abstract class BlockRender extends Namespaced {
|
||||||
@ -38,10 +37,6 @@ public abstract class BlockRender extends Namespaced {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeOptimized(ChunkRenderOptimizer optimizer) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean needsOwnRenderable() {
|
public boolean needsOwnRenderable() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,7 @@ public class BlockRenders {
|
|||||||
private static final AtlasGroup BLOCKS_ATLAS_GROUP =
|
private static final AtlasGroup BLOCKS_ATLAS_GROUP =
|
||||||
new AtlasGroup("Blocks", 1 << 12);
|
new AtlasGroup("Blocks", 1 << 12);
|
||||||
|
|
||||||
private static Texture grassTop = getTexture("grass_top");
|
private static Texture dirt = getTexture("dirt");
|
||||||
private static Texture grassSide = getTexture("grass_side");
|
|
||||||
private static Texture dirt = getTexture("grass_bottom");
|
|
||||||
private static Texture stone = getTexture("stone");
|
private static Texture stone = getTexture("stone");
|
||||||
private static Texture glass = getTexture("glass_clear");
|
private static Texture glass = getTexture("glass_clear");
|
||||||
private static Texture compass = getTexture("compass");
|
private static Texture compass = getTexture("compass");
|
||||||
@ -44,7 +42,6 @@ public class BlockRenders {
|
|||||||
private BlockRenders() {}
|
private BlockRenders() {}
|
||||||
|
|
||||||
public static void registerTest() {
|
public static void registerTest() {
|
||||||
register(new BlockRenderOpaqueCube("Test", "Grass", grassTop, dirt, grassSide, grassSide, grassSide, grassSide));
|
|
||||||
register(new BlockRenderOpaqueCube("Test", "Dirt", dirt, dirt, dirt, dirt, dirt, dirt));
|
register(new BlockRenderOpaqueCube("Test", "Dirt", dirt, dirt, dirt, dirt, dirt, dirt));
|
||||||
register(new BlockRenderOpaqueCube("Test", "Stone", stone, stone, stone, stone, stone, stone));
|
register(new BlockRenderOpaqueCube("Test", "Stone", stone, stone, stone, stone, stone, stone));
|
||||||
|
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package ru.windcorp.progressia.client.world.renders;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Faces;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizerCube.OpaqueTile;
|
||||||
|
import ru.windcorp.progressia.common.block.BlockFace;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
|
public class TileRenderGrass extends TileRender implements OpaqueTile {
|
||||||
|
|
||||||
|
private final Texture topTexture;
|
||||||
|
private final Texture sideTexture;
|
||||||
|
|
||||||
|
public TileRenderGrass(
|
||||||
|
String namespace, String name,
|
||||||
|
Texture top, Texture side
|
||||||
|
) {
|
||||||
|
super(namespace, name);
|
||||||
|
this.topTexture = top;
|
||||||
|
this.sideTexture = side;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Texture getTexture(BlockFace face) {
|
||||||
|
return (face == BlockFace.TOP) ? topTexture : sideTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpaque(BlockFace face) {
|
||||||
|
return face == BlockFace.TOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldRenderable createRenderable(BlockFace face) {
|
||||||
|
ShapeRenderProgram program = WorldRenderProgram.getDefault();
|
||||||
|
|
||||||
|
Vec3 color = Vectors.grab3().set(1, 1, 1);
|
||||||
|
Vec3 center = Vectors.grab3().set(0, 0, 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new Shape(
|
||||||
|
Usage.STATIC, WorldRenderProgram.getDefault(),
|
||||||
|
Faces.createBlockFace(
|
||||||
|
program, getTexture(face), color,
|
||||||
|
center, face, false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
Vectors.release(color);
|
||||||
|
Vectors.release(center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsOwnRenderable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,10 +8,11 @@ import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
|||||||
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
import ru.windcorp.progressia.client.graphics.model.WorldRenderable;
|
||||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizerCube.OpaqueTile;
|
||||||
import ru.windcorp.progressia.common.block.BlockFace;
|
import ru.windcorp.progressia.common.block.BlockFace;
|
||||||
import ru.windcorp.progressia.common.util.Vectors;
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
public class TileRenderSimple extends TileRender {
|
public class TileRenderSimple extends TileRender implements OpaqueTile {
|
||||||
|
|
||||||
private final Texture texture;
|
private final Texture texture;
|
||||||
|
|
||||||
@ -20,10 +21,16 @@ public class TileRenderSimple extends TileRender {
|
|||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Texture getTexture() {
|
@Override
|
||||||
|
public Texture getTexture(BlockFace face) {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpaque(BlockFace face) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldRenderable createRenderable(BlockFace face) {
|
public WorldRenderable createRenderable(BlockFace face) {
|
||||||
ShapeRenderProgram program = WorldRenderProgram.getDefault();
|
ShapeRenderProgram program = WorldRenderProgram.getDefault();
|
||||||
@ -35,7 +42,8 @@ public class TileRenderSimple extends TileRender {
|
|||||||
return new Shape(
|
return new Shape(
|
||||||
Usage.STATIC, WorldRenderProgram.getDefault(),
|
Usage.STATIC, WorldRenderProgram.getDefault(),
|
||||||
Faces.createBlockFace(
|
Faces.createBlockFace(
|
||||||
program, texture, color, center, face, false
|
program, getTexture(face), color,
|
||||||
|
center, face, false
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
@ -43,5 +51,10 @@ public class TileRenderSimple extends TileRender {
|
|||||||
Vectors.release(center);
|
Vectors.release(center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsOwnRenderable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,11 @@ public class TileRenders {
|
|||||||
private TileRenders() {}
|
private TileRenders() {}
|
||||||
|
|
||||||
public static void registerTest() {
|
public static void registerTest() {
|
||||||
|
register(new TileRenderGrass("Test", "Grass", getTexture("grass_top"), getTexture("grass_side")));
|
||||||
|
|
||||||
register(new TileRenderSimple("Test", "Stones", getTexture("stones")));
|
register(new TileRenderSimple("Test", "Stones", getTexture("stones")));
|
||||||
|
register(new TileRenderSimple("Test", "YellowFlowers", getTexture("yellow_flowers")));
|
||||||
|
register(new TileRenderSimple("Test", "Sand", getTexture("sand")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TileRender get(String name) {
|
public static TileRender get(String name) {
|
||||||
|
@ -17,15 +17,26 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package ru.windcorp.progressia.client.world.renders.cro;
|
package ru.windcorp.progressia.client.world.renders.cro;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
import ru.windcorp.progressia.client.graphics.model.Shape;
|
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||||
import ru.windcorp.progressia.client.world.ChunkRender;
|
import ru.windcorp.progressia.client.world.ChunkRender;
|
||||||
import ru.windcorp.progressia.client.world.renders.BlockRender;
|
import ru.windcorp.progressia.client.world.renders.BlockRender;
|
||||||
|
import ru.windcorp.progressia.client.world.renders.TileRender;
|
||||||
|
import ru.windcorp.progressia.common.block.BlockFace;
|
||||||
|
|
||||||
public abstract class ChunkRenderOptimizer {
|
public abstract class ChunkRenderOptimizer {
|
||||||
|
|
||||||
public abstract void startRender(ChunkRender chunk);
|
public abstract void startRender(ChunkRender chunk);
|
||||||
|
|
||||||
public abstract void processBlock(BlockRender block, int x, int y, int z);
|
public abstract void processBlock(
|
||||||
|
BlockRender block,
|
||||||
|
Vec3i posInChunk
|
||||||
|
);
|
||||||
|
|
||||||
|
public abstract void processTile(
|
||||||
|
TileRender tile,
|
||||||
|
Vec3i posInChunk, BlockFace face
|
||||||
|
);
|
||||||
|
|
||||||
public abstract Shape endRender();
|
public abstract Shape endRender();
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package ru.windcorp.progressia.client.world.renders.cro;
|
package ru.windcorp.progressia.client.world.renders.cro;
|
||||||
|
|
||||||
|
import static ru.windcorp.progressia.common.block.BlockFace.BLOCK_FACE_COUNT;
|
||||||
import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK;
|
import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK;
|
||||||
|
import static ru.windcorp.progressia.common.world.ChunkData.TILES_PER_FACE;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -33,7 +35,9 @@ import ru.windcorp.progressia.client.graphics.texture.Texture;
|
|||||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
import ru.windcorp.progressia.client.world.ChunkRender;
|
import ru.windcorp.progressia.client.world.ChunkRender;
|
||||||
import ru.windcorp.progressia.client.world.renders.BlockRender;
|
import ru.windcorp.progressia.client.world.renders.BlockRender;
|
||||||
|
import ru.windcorp.progressia.client.world.renders.TileRender;
|
||||||
import ru.windcorp.progressia.common.block.BlockFace;
|
import ru.windcorp.progressia.common.block.BlockFace;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
|
||||||
public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
||||||
|
|
||||||
@ -43,12 +47,58 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
|||||||
public boolean isBlockOpaque();
|
public boolean isBlockOpaque();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface OpaqueTile {
|
||||||
|
public Texture getTexture(BlockFace face);
|
||||||
|
public boolean isOpaque(BlockFace face);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BlockInfo {
|
||||||
|
OpaqueCube block;
|
||||||
|
final FaceInfo[] faces = new FaceInfo[BLOCK_FACE_COUNT];
|
||||||
|
|
||||||
|
{
|
||||||
|
for (int i = 0; i < faces.length; ++i) {
|
||||||
|
faces[i] = new FaceInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FaceInfo {
|
||||||
|
static final int NO_OPAQUE_TILES = -1;
|
||||||
|
|
||||||
|
int topOpaqueTile = NO_OPAQUE_TILES;
|
||||||
|
final OpaqueTile[] tiles = new OpaqueTile[TILES_PER_FACE];
|
||||||
|
int tileCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static final Vec3 COLOR_MULTIPLIER = new Vec3(1, 1, 1);
|
private static final Vec3 COLOR_MULTIPLIER = new Vec3(1, 1, 1);
|
||||||
|
|
||||||
private final OpaqueCube[][][] data =
|
// private final OpaqueCube[][][] blocks =
|
||||||
new OpaqueCube[BLOCKS_PER_CHUNK]
|
// new OpaqueCube[BLOCKS_PER_CHUNK]
|
||||||
[BLOCKS_PER_CHUNK]
|
// [BLOCKS_PER_CHUNK]
|
||||||
[BLOCKS_PER_CHUNK];
|
// [BLOCKS_PER_CHUNK];
|
||||||
|
//
|
||||||
|
// private final OpaqueTile[][][][][] tiles =
|
||||||
|
// new OpaqueTile[BLOCKS_PER_CHUNK]
|
||||||
|
// [BLOCKS_PER_CHUNK]
|
||||||
|
// [BLOCKS_PER_CHUNK]
|
||||||
|
// [BLOCK_FACE_COUNT]
|
||||||
|
// [TILES_PER_FACE];
|
||||||
|
|
||||||
|
private final BlockInfo[][][] data =
|
||||||
|
new BlockInfo[BLOCKS_PER_CHUNK]
|
||||||
|
[BLOCKS_PER_CHUNK]
|
||||||
|
[BLOCKS_PER_CHUNK];
|
||||||
|
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) {
|
||||||
|
for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) {
|
||||||
|
for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) {
|
||||||
|
data[x][y][z] = new BlockInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startRender(ChunkRender chunk) {
|
public void startRender(ChunkRender chunk) {
|
||||||
@ -56,19 +106,43 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processBlock(BlockRender block, int x, int y, int z) {
|
public void processBlock(BlockRender block, Vec3i pos) {
|
||||||
if (!(block instanceof OpaqueCube)) return;
|
if (!(block instanceof OpaqueCube)) return;
|
||||||
OpaqueCube opaqueCube = (OpaqueCube) block;
|
OpaqueCube opaqueCube = (OpaqueCube) block;
|
||||||
addBlock(x, y, z, opaqueCube);
|
addBlock(pos, opaqueCube);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addBlock(int x, int y, int z, OpaqueCube cube) {
|
@Override
|
||||||
data[x][y][z] = cube;
|
public void processTile(TileRender tile, Vec3i pos, BlockFace face) {
|
||||||
|
if (!(tile instanceof OpaqueTile)) return;
|
||||||
|
OpaqueTile opaqueTile = (OpaqueTile) tile;
|
||||||
|
addTile(pos, face, opaqueTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addBlock(Vec3i pos, OpaqueCube cube) {
|
||||||
|
getBlock(pos).block = cube;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OpaqueCube getBlock(Vec3i cursor) {
|
private void addTile(Vec3i pos, BlockFace face, OpaqueTile opaqueTile) {
|
||||||
|
FaceInfo faceInfo = getFace(pos, face);
|
||||||
|
|
||||||
|
int index = faceInfo.tileCount;
|
||||||
|
faceInfo.tileCount++;
|
||||||
|
|
||||||
|
faceInfo.tiles[index] = opaqueTile;
|
||||||
|
|
||||||
|
if (opaqueTile.isOpaque(face)) {
|
||||||
|
faceInfo.topOpaqueTile = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BlockInfo getBlock(Vec3i cursor) {
|
||||||
return data[cursor.x][cursor.y][cursor.z];
|
return data[cursor.x][cursor.y][cursor.z];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FaceInfo getFace(Vec3i cursor, BlockFace face) {
|
||||||
|
return getBlock(cursor).faces[face.getId()];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Shape endRender() {
|
public Shape endRender() {
|
||||||
@ -82,12 +156,8 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
|||||||
for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) {
|
for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) {
|
||||||
for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) {
|
for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) {
|
||||||
for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) {
|
for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) {
|
||||||
OpaqueCube block = getBlock(cursor);
|
processInnerFaces(cursor, shapeFaces::add);
|
||||||
|
processOuterFaces(cursor, shapeFaces::add);
|
||||||
if (block == null) continue;
|
|
||||||
|
|
||||||
processInnerFaces(block, cursor, shapeFaces::add);
|
|
||||||
processOuterFaces(block, cursor, shapeFaces::add);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,63 +168,83 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
|||||||
shapeFaces.toArray(new Face[shapeFaces.size()])
|
shapeFaces.toArray(new Face[shapeFaces.size()])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processInnerFaces(
|
|
||||||
OpaqueCube block,
|
|
||||||
Vec3i cursor,
|
|
||||||
Consumer<Face> output
|
|
||||||
) {
|
|
||||||
if (block.isBlockOpaque()) return;
|
|
||||||
|
|
||||||
for (BlockFace face : BlockFace.getFaces()) {
|
|
||||||
|
|
||||||
Texture texture = block.getTexture(face);
|
|
||||||
if (texture == null) continue;
|
|
||||||
|
|
||||||
output.accept(Faces.createBlockFace(
|
|
||||||
WorldRenderProgram.getDefault(),
|
|
||||||
texture,
|
|
||||||
COLOR_MULTIPLIER,
|
|
||||||
new Vec3(cursor.x, cursor.y, cursor.z),
|
|
||||||
face,
|
|
||||||
true
|
|
||||||
));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processOuterFaces(
|
private void processOuterFaces(
|
||||||
OpaqueCube block,
|
|
||||||
Vec3i cursor,
|
Vec3i cursor,
|
||||||
Consumer<Face> output
|
Consumer<Face> output
|
||||||
) {
|
) {
|
||||||
|
Vec3 faceOrigin = Vectors.grab3();
|
||||||
|
Vec3 offset = Vectors.grab3();
|
||||||
|
|
||||||
for (BlockFace face : BlockFace.getFaces()) {
|
for (BlockFace face : BlockFace.getFaces()) {
|
||||||
|
if (!shouldRenderOuterFace(cursor, face)) continue;
|
||||||
|
|
||||||
Texture texture = block.getTexture(face);
|
faceOrigin.set(cursor.x, cursor.y, cursor.z);
|
||||||
if (texture == null) continue;
|
offset
|
||||||
|
.set(face.getVector().x, face.getVector().y, face.getVector().z)
|
||||||
|
.mul(1f / 128);
|
||||||
|
|
||||||
if (!shouldRenderFace(cursor, face)) continue;
|
FaceInfo info = getFace(cursor, face);
|
||||||
|
|
||||||
output.accept(Faces.createBlockFace(
|
if (info.topOpaqueTile == FaceInfo.NO_OPAQUE_TILES) {
|
||||||
WorldRenderProgram.getDefault(),
|
OpaqueCube block = getBlock(cursor).block;
|
||||||
texture,
|
|
||||||
COLOR_MULTIPLIER,
|
if (block != null) {
|
||||||
new Vec3(cursor.x, cursor.y, cursor.z),
|
addFace(
|
||||||
face,
|
faceOrigin, face,
|
||||||
false
|
getBlock(cursor).block.getTexture(face),
|
||||||
));
|
output
|
||||||
|
);
|
||||||
|
|
||||||
|
faceOrigin.add(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int startLayer = info.topOpaqueTile;
|
||||||
|
if (startLayer == FaceInfo.NO_OPAQUE_TILES) {
|
||||||
|
startLayer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int layer = startLayer; layer < info.tileCount; ++layer) {
|
||||||
|
addFace(
|
||||||
|
faceOrigin, face,
|
||||||
|
info.tiles[layer].getTexture(face),
|
||||||
|
output
|
||||||
|
);
|
||||||
|
|
||||||
|
faceOrigin.add(offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vectors.release(offset);
|
||||||
|
Vectors.release(faceOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldRenderFace(Vec3i cursor, BlockFace face) {
|
private void addFace(
|
||||||
|
Vec3 cursor, BlockFace face,
|
||||||
|
Texture texture,
|
||||||
|
Consumer<Face> output
|
||||||
|
) {
|
||||||
|
if (texture == null) return;
|
||||||
|
|
||||||
|
output.accept(Faces.createBlockFace(
|
||||||
|
WorldRenderProgram.getDefault(),
|
||||||
|
texture,
|
||||||
|
COLOR_MULTIPLIER,
|
||||||
|
new Vec3(cursor),
|
||||||
|
face,
|
||||||
|
false
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldRenderOuterFace(Vec3i cursor, BlockFace face) {
|
||||||
cursor.add(face.getVector());
|
cursor.add(face.getVector());
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// TODO handle neighboring chunks properly
|
// TODO handle neighboring chunks properly
|
||||||
if (!isInBounds(cursor)) return true;
|
if (!isInBounds(cursor)) return true;
|
||||||
|
|
||||||
OpaqueCube adjacent = getBlock(cursor);
|
OpaqueCube adjacent = getBlock(cursor).block;
|
||||||
|
|
||||||
if (adjacent == null) return true;
|
if (adjacent == null) return true;
|
||||||
if (adjacent.isOpaque(face)) return false;
|
if (adjacent.isOpaque(face)) return false;
|
||||||
@ -166,6 +256,29 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processInnerFaces(
|
||||||
|
Vec3i cursor,
|
||||||
|
Consumer<Face> output
|
||||||
|
) {
|
||||||
|
// if (block.isBlockOpaque()) return;
|
||||||
|
//
|
||||||
|
// for (BlockFace face : BlockFace.getFaces()) {
|
||||||
|
//
|
||||||
|
// Texture texture = block.getTexture(face);
|
||||||
|
// if (texture == null) continue;
|
||||||
|
//
|
||||||
|
// output.accept(Faces.createBlockFace(
|
||||||
|
// WorldRenderProgram.getDefault(),
|
||||||
|
// texture,
|
||||||
|
// COLOR_MULTIPLIER,
|
||||||
|
// new Vec3(cursor.x, cursor.y, cursor.z),
|
||||||
|
// face,
|
||||||
|
// true
|
||||||
|
// ));
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isInBounds(Vec3i cursor) {
|
private boolean isInBounds(Vec3i cursor) {
|
||||||
return
|
return
|
||||||
isInBounds(cursor.x) &&
|
isInBounds(cursor.x) &&
|
||||||
|
@ -25,7 +25,6 @@ public class BlockDataRegistry {
|
|||||||
private static final Map<String, BlockData> REGISTRY = new HashMap<>();
|
private static final Map<String, BlockData> REGISTRY = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
register(new BlockData("Test", "Grass"));
|
|
||||||
register(new BlockData("Test", "Dirt"));
|
register(new BlockData("Test", "Dirt"));
|
||||||
register(new BlockData("Test", "Stone"));
|
register(new BlockData("Test", "Stone"));
|
||||||
register(new BlockData("Test", "Air"));
|
register(new BlockData("Test", "Air"));
|
||||||
|
@ -25,7 +25,10 @@ public class TileDataRegistry {
|
|||||||
private static final Map<String, TileData> REGISTRY = new HashMap<>();
|
private static final Map<String, TileData> REGISTRY = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
register(new TileData("Test", "Grass"));
|
||||||
register(new TileData("Test", "Stones"));
|
register(new TileData("Test", "Stones"));
|
||||||
|
register(new TileData("Test", "YellowFlowers"));
|
||||||
|
register(new TileData("Test", "Sand"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TileData get(String name) {
|
public static TileData get(String name) {
|
||||||
|
@ -59,12 +59,14 @@ public class ChunkData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tmp_generate() {
|
private void tmp_generate() {
|
||||||
BlockData grass = BlockDataRegistry.get("Test:Grass");
|
|
||||||
BlockData dirt = BlockDataRegistry.get("Test:Dirt");
|
BlockData dirt = BlockDataRegistry.get("Test:Dirt");
|
||||||
BlockData stone = BlockDataRegistry.get("Test:Stone");
|
BlockData stone = BlockDataRegistry.get("Test:Stone");
|
||||||
BlockData air = BlockDataRegistry.get("Test:Air");
|
BlockData air = BlockDataRegistry.get("Test:Air");
|
||||||
|
|
||||||
|
TileData grass = TileDataRegistry.get("Test:Grass");
|
||||||
TileData stones = TileDataRegistry.get("Test:Stones");
|
TileData stones = TileDataRegistry.get("Test:Stones");
|
||||||
|
TileData flowers = TileDataRegistry.get("Test:YellowFlowers");
|
||||||
|
TileData sand = TileDataRegistry.get("Test:Sand");
|
||||||
|
|
||||||
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();
|
||||||
@ -95,12 +97,26 @@ public class ChunkData {
|
|||||||
|
|
||||||
for (pos.z = BLOCKS_PER_CHUNK - 1; pos.z >= 0 && getBlock(pos) == air; --pos.z);
|
for (pos.z = BLOCKS_PER_CHUNK - 1; pos.z >= 0 && getBlock(pos) == air; --pos.z);
|
||||||
|
|
||||||
setBlock(pos, grass);
|
getTiles(pos, BlockFace.TOP).add(grass);
|
||||||
|
for (BlockFace face : BlockFace.getFaces()) {
|
||||||
|
if (face.getVector().z != 0) continue;
|
||||||
|
getTiles(pos, face).add(grass);
|
||||||
|
}
|
||||||
|
|
||||||
int hash = x*x * 13 ^ y*y * 37 ^ pos.z*pos.z * 129;
|
int hash = x*x * 19 ^ y*y * 41 ^ pos.z*pos.z * 147;
|
||||||
|
if (hash % 5 == 0) {
|
||||||
|
getTiles(pos, BlockFace.TOP).add(sand);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = x*x * 13 ^ y*y * 37 ^ pos.z*pos.z * 129;
|
||||||
if (hash % 5 == 0) {
|
if (hash % 5 == 0) {
|
||||||
getTiles(pos, BlockFace.TOP).add(stones);
|
getTiles(pos, BlockFace.TOP).add(stones);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash = x*x * 17 ^ y*y * 39 ^ pos.z*pos.z * 131;
|
||||||
|
if (hash % 9 == 0) {
|
||||||
|
getTiles(pos, BlockFace.TOP).add(flowers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,8 +234,8 @@ public class ChunkData {
|
|||||||
return
|
return
|
||||||
(blockInChunk.x == min && face == SOUTH ) ||
|
(blockInChunk.x == min && face == SOUTH ) ||
|
||||||
(blockInChunk.x == max && face == NORTH ) ||
|
(blockInChunk.x == max && face == NORTH ) ||
|
||||||
(blockInChunk.y == min && face == WEST ) ||
|
(blockInChunk.y == min && face == EAST ) ||
|
||||||
(blockInChunk.y == max && face == EAST ) ||
|
(blockInChunk.y == max && face == WEST ) ||
|
||||||
(blockInChunk.z == min && face == BOTTOM) ||
|
(blockInChunk.z == min && face == BOTTOM) ||
|
||||||
(blockInChunk.z == max && face == TOP );
|
(blockInChunk.z == max && face == TOP );
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
BIN
src/main/resources/assets/textures/tiles/grass_side.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
src/main/resources/assets/textures/tiles/sand.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
src/main/resources/assets/textures/tiles/yellow_flowers.png
Normal file
After Width: | Height: | Size: 334 B |