Refactored CROs and CROCube, Faces.createBlockFace and Camera
- Multiple ChunkRenderOptimizers can now optimize one block if desired - CROs require that an interface is implemented, not class extended - ChunkRenderOptimizerCube has been refactored: - Blocks that a not opaque are now optimized - Blocks have per-face opacity - Blocks can render inner faces - Example: test glass - Code is now readable - Faces was rewritten to support flipping - .createBlockFace is now readable - Camera now manipulates coordinate systems in a more obvious way - Camera now uses world coordinate system - Z is up - Yaw 0 looks to the North (+X) - Positive pitch is up - Improved control code readability somewhat - Fixed test UI compass
This commit is contained in:
parent
bdb458b911
commit
a9896fa3e1
@ -73,7 +73,7 @@ public class LayerTestUI extends AssembledFlatLayer {
|
||||
target.addCustomRenderer(new LambdaModel(LambdaModel.lambdaBuilder()
|
||||
.addDynamicPart(
|
||||
target.createRectagle(0, 0, texSize, texSize, 0xFFFFFF, compassFg),
|
||||
mat -> mat.translate(texSize/2, texSize/2, 0).rotateZ(-LayerWorld.tmp_the_camera.getYaw()).translate(-texSize/2, -texSize/2, 0)
|
||||
mat -> mat.translate(texSize/2, texSize/2, 0).rotateZ(LayerWorld.tmp_the_camera.getYaw()).translate(-texSize/2, -texSize/2, 0)
|
||||
)
|
||||
));
|
||||
target.popTransform();
|
||||
|
@ -230,7 +230,8 @@ public class RenderTarget {
|
||||
createVectorFromRGBInt(color),
|
||||
new Vec3(x, y, depth),
|
||||
new Vec3(width, 0, 0),
|
||||
new Vec3(0, height, 0)
|
||||
new Vec3(0, height, 0),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
Face createFace() {
|
||||
return Faces.createRectangle(
|
||||
getProgram(),
|
||||
texture, color, origin, width, height
|
||||
texture, color, origin, width, height, false
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,112 @@
|
||||
package ru.windcorp.progressia.client.graphics.model;
|
||||
|
||||
import static ru.windcorp.progressia.common.block.BlockFace.*;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.common.block.BlockFace;
|
||||
|
||||
class BlockFaceVectors {
|
||||
|
||||
private static BlockFaceVectors createInner(BlockFaceVectors outer) {
|
||||
ImmutableMap.Builder<BlockFace, Vec3> originBuilder =
|
||||
ImmutableMap.builderWithExpectedSize(count());
|
||||
|
||||
ImmutableMap.Builder<BlockFace, Vec3> widthBuilder =
|
||||
ImmutableMap.builderWithExpectedSize(count());
|
||||
|
||||
ImmutableMap.Builder<BlockFace, Vec3> heightBuilder =
|
||||
ImmutableMap.builderWithExpectedSize(count());
|
||||
|
||||
for (BlockFace face : getFaces()) {
|
||||
Vec3 width = outer.getWidth(face);
|
||||
Vec3 height = outer.getHeight(face);
|
||||
|
||||
originBuilder.put(face,
|
||||
new Vec3(outer.getOrigin(face))
|
||||
);
|
||||
|
||||
widthBuilder.put(face, new Vec3(width));
|
||||
heightBuilder.put(face, new Vec3(height));
|
||||
}
|
||||
|
||||
return new BlockFaceVectors(
|
||||
originBuilder.build(),
|
||||
widthBuilder.build(),
|
||||
heightBuilder.build()
|
||||
);
|
||||
}
|
||||
|
||||
private static final BlockFaceVectors OUTER;
|
||||
private static final BlockFaceVectors INNER;
|
||||
|
||||
static {
|
||||
OUTER = new BlockFaceVectors(
|
||||
ImmutableMap.<BlockFace, Vec3>builderWithExpectedSize(count())
|
||||
|
||||
.put(TOP, new Vec3(-0.5f, +0.5f, +0.5f))
|
||||
.put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
.put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f))
|
||||
.put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f))
|
||||
.put(WEST, new Vec3(+0.5f, +0.5f, -0.5f))
|
||||
.put(EAST, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
|
||||
.build(),
|
||||
|
||||
ImmutableMap.<BlockFace, Vec3>builderWithExpectedSize(count())
|
||||
|
||||
.put(TOP, new Vec3( 0, -1, 0))
|
||||
.put(BOTTOM, new Vec3( 0, +1, 0))
|
||||
.put(NORTH, new Vec3( 0, +1, 0))
|
||||
.put(SOUTH, new Vec3( 0, -1, 0))
|
||||
.put(WEST, new Vec3(-1, 0, 0))
|
||||
.put(EAST, new Vec3(+1, 0, 0))
|
||||
|
||||
.build(),
|
||||
|
||||
ImmutableMap.<BlockFace, Vec3>builderWithExpectedSize(count())
|
||||
|
||||
.put(TOP, new Vec3(+1, 0, 0))
|
||||
.put(BOTTOM, new Vec3(+1, 0, 0))
|
||||
.put(NORTH, new Vec3( 0, 0, +1))
|
||||
.put(SOUTH, new Vec3( 0, 0, +1))
|
||||
.put(WEST, new Vec3( 0, 0, +1))
|
||||
.put(EAST, new Vec3( 0, 0, +1))
|
||||
|
||||
.build()
|
||||
);
|
||||
|
||||
INNER = createInner(OUTER);
|
||||
}
|
||||
|
||||
public static BlockFaceVectors get(boolean inner) {
|
||||
return inner ? INNER : OUTER;
|
||||
}
|
||||
|
||||
private final ImmutableMap<BlockFace, Vec3> origins;
|
||||
private final ImmutableMap<BlockFace, Vec3> widths;
|
||||
private final ImmutableMap<BlockFace, Vec3> heights;
|
||||
|
||||
public BlockFaceVectors(
|
||||
ImmutableMap<BlockFace, Vec3> origins,
|
||||
ImmutableMap<BlockFace, Vec3> widths,
|
||||
ImmutableMap<BlockFace, Vec3> heights
|
||||
) {
|
||||
this.origins = origins;
|
||||
this.widths = widths;
|
||||
this.heights = heights;
|
||||
}
|
||||
|
||||
public Vec3 getOrigin(BlockFace face) {
|
||||
return origins.get(face);
|
||||
}
|
||||
|
||||
public Vec3 getWidth(BlockFace face) {
|
||||
return widths.get(face);
|
||||
}
|
||||
|
||||
public Vec3 getHeight(BlockFace face) {
|
||||
return heights.get(face);
|
||||
}
|
||||
}
|
@ -35,7 +35,8 @@ public class Faces {
|
||||
Vec3 colorMultiplier,
|
||||
Vec3 origin,
|
||||
Vec3 width,
|
||||
Vec3 height
|
||||
Vec3 height,
|
||||
boolean flip
|
||||
) {
|
||||
VertexBuilder builder = program.getVertexBuilder();
|
||||
|
||||
@ -60,13 +61,18 @@ public class Faces {
|
||||
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(),
|
||||
ShortBuffer.wrap(new short[] {
|
||||
3, 1, 0,
|
||||
2, 3, 0
|
||||
})
|
||||
buffer
|
||||
);
|
||||
}
|
||||
|
||||
@ -75,59 +81,20 @@ public class Faces {
|
||||
Texture texture,
|
||||
Vec3 colorMultiplier,
|
||||
Vec3 blockCenter,
|
||||
BlockFace face
|
||||
BlockFace face,
|
||||
boolean inner
|
||||
) {
|
||||
if (face == BlockFace.TOP) {
|
||||
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,
|
||||
blockCenter.add(-0.5f, +0.5f, +0.5f),
|
||||
new Vec3( 0, -1, 0),
|
||||
new Vec3(+1, 0, 0)
|
||||
program, texture, colorMultiplier,
|
||||
origin, width, height,
|
||||
inner
|
||||
);
|
||||
} else if (face == BlockFace.BOTTOM) {
|
||||
return createRectangle(
|
||||
program,
|
||||
texture, colorMultiplier,
|
||||
blockCenter.add(-0.5f, -0.5f, -0.5f),
|
||||
new Vec3( 0, +1, 0),
|
||||
new Vec3(+1, 0, 0)
|
||||
);
|
||||
} else if (face == BlockFace.NORTH) {
|
||||
return createRectangle(
|
||||
program,
|
||||
texture, colorMultiplier,
|
||||
blockCenter.add(+0.5f, -0.5f, -0.5f),
|
||||
new Vec3( 0, +1, 0),
|
||||
new Vec3( 0, 0, +1)
|
||||
);
|
||||
} else if (face == BlockFace.SOUTH) {
|
||||
return createRectangle(
|
||||
program,
|
||||
texture, colorMultiplier,
|
||||
blockCenter.add(-0.5f, +0.5f, -0.5f),
|
||||
new Vec3( 0, -1, 0),
|
||||
new Vec3( 0, 0, +1)
|
||||
);
|
||||
} else if (face == BlockFace.EAST) {
|
||||
return createRectangle(
|
||||
program,
|
||||
texture, colorMultiplier,
|
||||
blockCenter.add(-0.5f, -0.5f, -0.5f),
|
||||
new Vec3(+1, 0, 0),
|
||||
new Vec3( 0, 0, +1)
|
||||
);
|
||||
} else if (face == BlockFace.WEST) {
|
||||
return createRectangle(
|
||||
program,
|
||||
texture, colorMultiplier,
|
||||
blockCenter.add(+0.5f, +0.5f, -0.5f),
|
||||
new Vec3(-1, 0, 0),
|
||||
new Vec3( 0, 0, +1)
|
||||
);
|
||||
} else {
|
||||
throw new NullPointerException("face");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ public class Shapes {
|
||||
topTexture, colorMultiplier,
|
||||
faceOrigin.set(origin).add(height).add(width),
|
||||
faceWidth.set(width).negate(),
|
||||
depth
|
||||
depth,
|
||||
false
|
||||
);
|
||||
|
||||
Face bottom = Faces.createRectangle(
|
||||
@ -58,7 +59,8 @@ public class Shapes {
|
||||
bottomTexture, colorMultiplier,
|
||||
origin,
|
||||
width,
|
||||
depth
|
||||
depth,
|
||||
false
|
||||
);
|
||||
|
||||
Face north = Faces.createRectangle(
|
||||
@ -66,7 +68,8 @@ public class Shapes {
|
||||
northTexture, colorMultiplier,
|
||||
faceOrigin.set(origin).add(depth),
|
||||
width,
|
||||
height
|
||||
height,
|
||||
false
|
||||
);
|
||||
|
||||
Face south = Faces.createRectangle(
|
||||
@ -74,7 +77,8 @@ public class Shapes {
|
||||
southTexture, colorMultiplier,
|
||||
faceOrigin.set(origin).add(width),
|
||||
faceWidth.set(width).negate(),
|
||||
height
|
||||
height,
|
||||
false
|
||||
);
|
||||
|
||||
Face east = Faces.createRectangle(
|
||||
@ -82,7 +86,8 @@ public class Shapes {
|
||||
eastTexture, colorMultiplier,
|
||||
origin,
|
||||
depth,
|
||||
height
|
||||
height,
|
||||
false
|
||||
);
|
||||
|
||||
Face west = Faces.createRectangle(
|
||||
@ -90,7 +95,8 @@ public class Shapes {
|
||||
westTexture, colorMultiplier,
|
||||
faceOrigin.set(origin).add(width).add(depth),
|
||||
faceWidth.set(depth).negate(),
|
||||
height
|
||||
height,
|
||||
false
|
||||
);
|
||||
|
||||
Shape result = new Shape(
|
||||
|
@ -43,16 +43,33 @@ public class Camera {
|
||||
public Camera() {}
|
||||
|
||||
public void apply(WorldRenderHelper helper) {
|
||||
applyPerspective(helper);
|
||||
rotateCoordinateSystem(helper);
|
||||
|
||||
applyDirection(helper);
|
||||
applyPosition(helper);
|
||||
}
|
||||
|
||||
private void applyPerspective(WorldRenderHelper helper) {
|
||||
Mat4 previous = helper.getViewTransform();
|
||||
|
||||
Glm.perspective(
|
||||
computeFovY(),
|
||||
GraphicsInterface.getAspectRatio(),
|
||||
0.01f, 10000.0f,
|
||||
helper.pushViewTransform()
|
||||
).mul(previous);
|
||||
}
|
||||
|
||||
helper.pushViewTransform().rotateX(pitch).rotateY(yaw);
|
||||
private void rotateCoordinateSystem(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().rotateX(-PI / 2).rotateZ(PI / 2);
|
||||
}
|
||||
|
||||
private void applyDirection(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().rotateY(pitch).rotateZ(yaw);
|
||||
}
|
||||
|
||||
private void applyPosition(WorldRenderHelper helper) {
|
||||
helper.pushViewTransform().translate(position.negate());
|
||||
position.negate();
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ public class LayerWorld extends Layer {
|
||||
public static Camera tmp_the_camera;
|
||||
|
||||
private final Camera camera = new Camera(
|
||||
new Vec3(8, 8, 8),
|
||||
0, 0,
|
||||
new Vec3(-6, -6, 20),
|
||||
(float) Math.toRadians(-40), (float) Math.toRadians(-45),
|
||||
(float) Math.toRadians(70)
|
||||
);
|
||||
|
||||
@ -48,9 +48,9 @@ public class LayerWorld extends Layer {
|
||||
|
||||
private final Mat3 angMat = new Mat3();
|
||||
|
||||
private int movementX = 0;
|
||||
private int movementY = 0;
|
||||
private int movementZ = 0;
|
||||
private int movementForward = 0;
|
||||
private int movementRight = 0;
|
||||
private int movementUp = 0;
|
||||
|
||||
private static final boolean I_WANT_TO_THROW_UP = false;
|
||||
private float shakeParam = 0;
|
||||
@ -81,12 +81,12 @@ public class LayerWorld extends Layer {
|
||||
renderWorld();
|
||||
helper.reset();
|
||||
|
||||
angMat.set().rotateY(-camera.getYaw());
|
||||
angMat.set().rotateZ(-camera.getYaw());
|
||||
|
||||
tmp.set(movementX, 0, movementZ);
|
||||
if (movementX != 0 && movementZ != 0) tmp.normalize();
|
||||
tmp.set(movementForward, -movementRight, 0);
|
||||
if (movementForward != 0 && movementRight != 0) tmp.normalize();
|
||||
angMat.mul_(tmp); // bug in jglm
|
||||
tmp.y = movementY;
|
||||
tmp.z = movementUp;
|
||||
tmp.mul(0.1f);
|
||||
tmp.sub(velocity);
|
||||
tmp.mul(0.1f);
|
||||
@ -141,22 +141,22 @@ public class LayerWorld extends Layer {
|
||||
|
||||
switch (event.getKey()) {
|
||||
case GLFW.GLFW_KEY_W:
|
||||
movementZ += -1 * multiplier;
|
||||
movementForward += +1 * multiplier;
|
||||
break;
|
||||
case GLFW.GLFW_KEY_S:
|
||||
movementZ += +1 * multiplier;
|
||||
movementForward += -1 * multiplier;
|
||||
break;
|
||||
case GLFW.GLFW_KEY_A:
|
||||
movementX += -1 * multiplier;
|
||||
movementRight += -1 * multiplier;
|
||||
break;
|
||||
case GLFW.GLFW_KEY_D:
|
||||
movementX += +1 * multiplier;
|
||||
movementRight += +1 * multiplier;
|
||||
break;
|
||||
case GLFW.GLFW_KEY_SPACE:
|
||||
movementY += +1 * multiplier;
|
||||
movementUp += +1 * multiplier;
|
||||
break;
|
||||
case GLFW.GLFW_KEY_LEFT_SHIFT:
|
||||
movementY += -1 * multiplier;
|
||||
movementUp += -1 * multiplier;
|
||||
break;
|
||||
|
||||
case GLFW.GLFW_KEY_ESCAPE:
|
||||
@ -190,7 +190,7 @@ public class LayerWorld extends Layer {
|
||||
if (!flag) return;
|
||||
|
||||
final float yawScale = 0.002f;
|
||||
final float pitchScale = -yawScale;
|
||||
final float pitchScale = yawScale;
|
||||
|
||||
camera.turn(
|
||||
(float) (event.getChangeY() * pitchScale),
|
||||
|
@ -56,8 +56,6 @@ public class WorldRender {
|
||||
}
|
||||
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
renderer.pushTransform().rotateX(-Math.PI / 2);
|
||||
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.render(renderer);
|
||||
}
|
||||
|
@ -58,4 +58,9 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsOwnRenderable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||
import ru.windcorp.progressia.client.graphics.model.Face;
|
||||
import ru.windcorp.progressia.client.graphics.model.Faces;
|
||||
@ -32,7 +34,6 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||
import ru.windcorp.progressia.client.world.ChunkRender;
|
||||
import ru.windcorp.progressia.client.world.renders.BlockRender;
|
||||
import ru.windcorp.progressia.common.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
|
||||
public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
||||
|
||||
@ -42,122 +43,51 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
||||
public boolean isBlockOpaque();
|
||||
}
|
||||
|
||||
private static final int BLOCK_MASK = 1 << 7;
|
||||
|
||||
private static final BlockFace[] GOOD_FACES = new BlockFace[] {
|
||||
BlockFace.TOP, BlockFace.NORTH, BlockFace.WEST
|
||||
};
|
||||
|
||||
private static final Vec3 COLOR_MULTIPLIER = new Vec3(1, 1, 1);
|
||||
|
||||
private final byte[][][] data = new byte[BLOCKS_PER_CHUNK + 1]
|
||||
[BLOCKS_PER_CHUNK + 1]
|
||||
[BLOCKS_PER_CHUNK + 1];
|
||||
|
||||
private ChunkRender chunk;
|
||||
|
||||
private final Vec3 blockCenter = new Vec3();
|
||||
private final OpaqueCube[][][] data =
|
||||
new OpaqueCube[BLOCKS_PER_CHUNK]
|
||||
[BLOCKS_PER_CHUNK]
|
||||
[BLOCKS_PER_CHUNK];
|
||||
|
||||
@Override
|
||||
public void startRender(ChunkRender chunk) {
|
||||
this.chunk = chunk;
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processBlock(BlockRender block, int x, int y, int z) {
|
||||
if (!(block instanceof OpaqueCube)) return;
|
||||
OpaqueCube opaqueCube = (OpaqueCube) block;
|
||||
|
||||
if (!opaqueCube.isBlockOpaque()) return; // FIXME
|
||||
|
||||
addFace(x, y, z, BlockFace.TOP);
|
||||
addFace(x, y, z, BlockFace.BOTTOM);
|
||||
addFace(x, y, z, BlockFace.NORTH);
|
||||
addFace(x, y, z, BlockFace.SOUTH);
|
||||
addFace(x, y, z, BlockFace.EAST);
|
||||
addFace(x, y, z, BlockFace.WEST);
|
||||
addBlock(x, y, z);
|
||||
addBlock(x, y, z, opaqueCube);
|
||||
}
|
||||
|
||||
protected void addFace(int x, int y, int z, BlockFace face) {
|
||||
if (face == BlockFace.BOTTOM) {
|
||||
z -= 1;
|
||||
face = BlockFace.TOP;
|
||||
} else if (face == BlockFace.SOUTH) {
|
||||
x -= 1;
|
||||
face = BlockFace.NORTH;
|
||||
} else if (face == BlockFace.EAST) {
|
||||
y -= 1;
|
||||
face = BlockFace.WEST;
|
||||
protected void addBlock(int x, int y, int z, OpaqueCube cube) {
|
||||
data[x][y][z] = cube;
|
||||
}
|
||||
|
||||
data[x + 1][y + 1][z + 1] ^= 1 << getBit(face);
|
||||
}
|
||||
|
||||
protected void addBlock(int x, int y, int z) {
|
||||
data[x + 1][y + 1][z + 1] |= BLOCK_MASK;
|
||||
}
|
||||
|
||||
protected boolean hasFace(int x, int y, int z, BlockFace face) {
|
||||
if (face == BlockFace.BOTTOM) {
|
||||
z -= 1;
|
||||
face = BlockFace.TOP;
|
||||
} else if (face == BlockFace.SOUTH) {
|
||||
x -= 1;
|
||||
face = BlockFace.NORTH;
|
||||
} else if (face == BlockFace.EAST) {
|
||||
y -= 1;
|
||||
face = BlockFace.WEST;
|
||||
}
|
||||
|
||||
return (data[x + 1][y + 1][z + 1] & 1 << getBit(face)) != 0;
|
||||
}
|
||||
|
||||
protected boolean hasBlock(int x, int y, int z) {
|
||||
return (data[x + 1][y + 1][z + 1] & BLOCK_MASK) != 0;
|
||||
protected OpaqueCube getBlock(Vec3i cursor) {
|
||||
return data[cursor.x][cursor.y][cursor.z];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape endRender() {
|
||||
|
||||
Collection<Face> shapeFaces = new ArrayList<>(
|
||||
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 +
|
||||
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
|
||||
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
|
||||
);
|
||||
|
||||
for (int x = -1; x < ChunkData.BLOCKS_PER_CHUNK; ++x) {
|
||||
for (int y = -1; y < ChunkData.BLOCKS_PER_CHUNK; ++y) {
|
||||
for (int z = -1; z < ChunkData.BLOCKS_PER_CHUNK; ++z) {
|
||||
for (BlockFace face : GOOD_FACES) {
|
||||
Vec3i cursor = new Vec3i();
|
||||
|
||||
if (!hasFace(x, y, z, face)) continue;
|
||||
for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) {
|
||||
for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) {
|
||||
for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) {
|
||||
OpaqueCube block = getBlock(cursor);
|
||||
|
||||
Face shapeFace = null;
|
||||
if (block == null) continue;
|
||||
|
||||
if (!hasBlock(x, y, z)) {
|
||||
if (face == BlockFace.TOP) {
|
||||
shapeFace = createFace(
|
||||
x, y, z + 1,
|
||||
BlockFace.BOTTOM
|
||||
);
|
||||
} else if (face == BlockFace.NORTH) {
|
||||
shapeFace = createFace(
|
||||
x + 1, y, z,
|
||||
BlockFace.SOUTH
|
||||
);
|
||||
} else if (face == BlockFace.WEST) {
|
||||
shapeFace = createFace(
|
||||
x, y + 1, z,
|
||||
BlockFace.EAST
|
||||
);
|
||||
}
|
||||
} else {
|
||||
shapeFace = createFace(x, y, z, face);
|
||||
}
|
||||
|
||||
shapeFaces.add(shapeFace);
|
||||
|
||||
}
|
||||
processInnerFaces(block, cursor, shapeFaces::add);
|
||||
processOuterFaces(block, cursor, shapeFaces::add);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,29 +99,82 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
|
||||
);
|
||||
}
|
||||
|
||||
private Face createFace(int x, int y, int z, BlockFace face) {
|
||||
OpaqueCube blockRender =
|
||||
(OpaqueCube) chunk.getBlock(x, y, z);
|
||||
Texture texture = blockRender.getTexture(face);
|
||||
private void processInnerFaces(
|
||||
OpaqueCube block,
|
||||
Vec3i cursor,
|
||||
Consumer<Face> output
|
||||
) {
|
||||
if (block.isBlockOpaque()) return;
|
||||
|
||||
return Faces.createBlockFace(
|
||||
for (BlockFace face : BlockFace.getFaces()) {
|
||||
|
||||
Texture texture = block.getTexture(face);
|
||||
if (texture == null) continue;
|
||||
|
||||
output.accept(Faces.createBlockFace(
|
||||
WorldRenderProgram.getDefault(),
|
||||
texture,
|
||||
COLOR_MULTIPLIER,
|
||||
blockCenter.set(x, y, z),
|
||||
face
|
||||
);
|
||||
new Vec3(cursor.x, cursor.y, cursor.z),
|
||||
face,
|
||||
true
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO refactor
|
||||
private static int getBit(BlockFace face) {
|
||||
if (face == BlockFace.TOP) return 0;
|
||||
if (face == BlockFace.BOTTOM) return 1;
|
||||
if (face == BlockFace.NORTH) return 2;
|
||||
if (face == BlockFace.SOUTH) return 3;
|
||||
if (face == BlockFace.WEST) return 4;
|
||||
if (face == BlockFace.EAST) return 5;
|
||||
return -1;
|
||||
private void processOuterFaces(
|
||||
OpaqueCube block,
|
||||
Vec3i cursor,
|
||||
Consumer<Face> output
|
||||
) {
|
||||
for (BlockFace face : BlockFace.getFaces()) {
|
||||
|
||||
Texture texture = block.getTexture(face);
|
||||
if (texture == null) continue;
|
||||
|
||||
if (!shouldRenderFace(cursor, face)) continue;
|
||||
|
||||
output.accept(Faces.createBlockFace(
|
||||
WorldRenderProgram.getDefault(),
|
||||
texture,
|
||||
COLOR_MULTIPLIER,
|
||||
new Vec3(cursor.x, cursor.y, cursor.z),
|
||||
face,
|
||||
false
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldRenderFace(Vec3i cursor, BlockFace face) {
|
||||
cursor.add(face.getVector());
|
||||
try {
|
||||
|
||||
// TODO handle neighboring chunks properly
|
||||
if (!isInBounds(cursor)) return true;
|
||||
|
||||
OpaqueCube adjacent = getBlock(cursor);
|
||||
|
||||
if (adjacent == null) return true;
|
||||
if (adjacent.isOpaque(face)) return false;
|
||||
|
||||
return true;
|
||||
|
||||
} finally {
|
||||
cursor.sub(face.getVector());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInBounds(Vec3i cursor) {
|
||||
return
|
||||
isInBounds(cursor.x) &&
|
||||
isInBounds(cursor.y) &&
|
||||
isInBounds(cursor.z);
|
||||
}
|
||||
|
||||
private boolean isInBounds(int c) {
|
||||
return c >= 0 && c < BLOCKS_PER_CHUNK;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,14 +26,25 @@ public final class BlockFace extends BlockRelation {
|
||||
BOTTOM = new BlockFace( 0, 0, -1, false),
|
||||
NORTH = new BlockFace(+1, 0, 0, true),
|
||||
SOUTH = new BlockFace(-1, 0, 0, false),
|
||||
WEST = new BlockFace( 0, +1, 0, true),
|
||||
EAST = new BlockFace( 0, -1, 0, false);
|
||||
WEST = new BlockFace( 0, +1, 0, false),
|
||||
EAST = new BlockFace( 0, -1, 0, true);
|
||||
|
||||
private static final ImmutableList<BlockFace> ALL_VALUES =
|
||||
private static final ImmutableList<BlockFace> ALL_FACES =
|
||||
ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST);
|
||||
|
||||
public static ImmutableList<BlockFace> getValues() {
|
||||
return ALL_VALUES;
|
||||
private static final ImmutableList<BlockFace> PRIMARY_FACES =
|
||||
ImmutableList.of(TOP, NORTH, WEST);
|
||||
|
||||
public static ImmutableList<BlockFace> getFaces() {
|
||||
return ALL_FACES;
|
||||
}
|
||||
|
||||
public static ImmutableList<BlockFace> getPrimaryFaces() {
|
||||
return PRIMARY_FACES;
|
||||
}
|
||||
|
||||
public static int count() {
|
||||
return ALL_FACES.size();
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -3,7 +3,7 @@
|
||||
varying vec3 varyingNormals;
|
||||
|
||||
void applyShading() {
|
||||
vec3 light = normalize(vec3(0.5, 1.0, 0.2));
|
||||
vec3 light = normalize(vec3(0.5, -0.2, 1.0));
|
||||
vec3 normal = varyingNormals;
|
||||
|
||||
float angleCos = dot(normal, light);
|
||||
|
Reference in New Issue
Block a user