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:
OLEGSHA 2020-08-26 01:34:32 +03:00
parent bdb458b911
commit a9896fa3e1
13 changed files with 309 additions and 209 deletions

View File

@ -73,7 +73,7 @@ public class LayerTestUI extends AssembledFlatLayer {
target.addCustomRenderer(new LambdaModel(LambdaModel.lambdaBuilder() target.addCustomRenderer(new LambdaModel(LambdaModel.lambdaBuilder()
.addDynamicPart( .addDynamicPart(
target.createRectagle(0, 0, texSize, texSize, 0xFFFFFF, compassFg), 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(); target.popTransform();

View File

@ -230,7 +230,8 @@ public class RenderTarget {
createVectorFromRGBInt(color), createVectorFromRGBInt(color),
new Vec3(x, y, depth), new Vec3(x, y, depth),
new Vec3(width, 0, 0), new Vec3(width, 0, 0),
new Vec3(0, height, 0) new Vec3(0, height, 0),
false
); );
} }

View File

@ -142,7 +142,7 @@ public abstract class SpriteTypeface extends Typeface {
Face createFace() { Face createFace() {
return Faces.createRectangle( return Faces.createRectangle(
getProgram(), getProgram(),
texture, color, origin, width, height texture, color, origin, width, height, false
); );
} }

View File

@ -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);
}
}

View File

@ -35,7 +35,8 @@ public class Faces {
Vec3 colorMultiplier, Vec3 colorMultiplier,
Vec3 origin, Vec3 origin,
Vec3 width, Vec3 width,
Vec3 height Vec3 height,
boolean flip
) { ) {
VertexBuilder builder = program.getVertexBuilder(); VertexBuilder builder = program.getVertexBuilder();
@ -60,13 +61,18 @@ public class Faces {
texCoords.set(1, 1) 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( return new Face(
texture, texture,
builder.assemble(), builder.assemble(),
ShortBuffer.wrap(new short[] { buffer
3, 1, 0,
2, 3, 0
})
); );
} }
@ -75,59 +81,20 @@ public class Faces {
Texture texture, Texture texture,
Vec3 colorMultiplier, Vec3 colorMultiplier,
Vec3 blockCenter, 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( return createRectangle(
program, program, texture, colorMultiplier,
texture, colorMultiplier, origin, width, height,
blockCenter.add(-0.5f, +0.5f, +0.5f), inner
new Vec3( 0, -1, 0),
new Vec3(+1, 0, 0)
); );
} 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");
}
} }
} }

View File

@ -50,7 +50,8 @@ public class Shapes {
topTexture, colorMultiplier, topTexture, colorMultiplier,
faceOrigin.set(origin).add(height).add(width), faceOrigin.set(origin).add(height).add(width),
faceWidth.set(width).negate(), faceWidth.set(width).negate(),
depth depth,
false
); );
Face bottom = Faces.createRectangle( Face bottom = Faces.createRectangle(
@ -58,7 +59,8 @@ public class Shapes {
bottomTexture, colorMultiplier, bottomTexture, colorMultiplier,
origin, origin,
width, width,
depth depth,
false
); );
Face north = Faces.createRectangle( Face north = Faces.createRectangle(
@ -66,7 +68,8 @@ public class Shapes {
northTexture, colorMultiplier, northTexture, colorMultiplier,
faceOrigin.set(origin).add(depth), faceOrigin.set(origin).add(depth),
width, width,
height height,
false
); );
Face south = Faces.createRectangle( Face south = Faces.createRectangle(
@ -74,7 +77,8 @@ public class Shapes {
southTexture, colorMultiplier, southTexture, colorMultiplier,
faceOrigin.set(origin).add(width), faceOrigin.set(origin).add(width),
faceWidth.set(width).negate(), faceWidth.set(width).negate(),
height height,
false
); );
Face east = Faces.createRectangle( Face east = Faces.createRectangle(
@ -82,7 +86,8 @@ public class Shapes {
eastTexture, colorMultiplier, eastTexture, colorMultiplier,
origin, origin,
depth, depth,
height height,
false
); );
Face west = Faces.createRectangle( Face west = Faces.createRectangle(
@ -90,7 +95,8 @@ public class Shapes {
westTexture, colorMultiplier, westTexture, colorMultiplier,
faceOrigin.set(origin).add(width).add(depth), faceOrigin.set(origin).add(width).add(depth),
faceWidth.set(depth).negate(), faceWidth.set(depth).negate(),
height height,
false
); );
Shape result = new Shape( Shape result = new Shape(

View File

@ -43,16 +43,33 @@ public class Camera {
public Camera() {} public Camera() {}
public void apply(WorldRenderHelper helper) { public void apply(WorldRenderHelper helper) {
applyPerspective(helper);
rotateCoordinateSystem(helper);
applyDirection(helper);
applyPosition(helper);
}
private void applyPerspective(WorldRenderHelper helper) {
Mat4 previous = helper.getViewTransform(); Mat4 previous = helper.getViewTransform();
Glm.perspective( Glm.perspective(
computeFovY(), computeFovY(),
GraphicsInterface.getAspectRatio(), GraphicsInterface.getAspectRatio(),
0.01f, 10000.0f, 0.01f, 10000.0f,
helper.pushViewTransform() helper.pushViewTransform()
).mul(previous); ).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()); helper.pushViewTransform().translate(position.negate());
position.negate(); position.negate();
} }

View File

@ -38,8 +38,8 @@ public class LayerWorld extends Layer {
public static Camera tmp_the_camera; public static Camera tmp_the_camera;
private final Camera camera = new Camera( private final Camera camera = new Camera(
new Vec3(8, 8, 8), new Vec3(-6, -6, 20),
0, 0, (float) Math.toRadians(-40), (float) Math.toRadians(-45),
(float) Math.toRadians(70) (float) Math.toRadians(70)
); );
@ -48,9 +48,9 @@ public class LayerWorld extends Layer {
private final Mat3 angMat = new Mat3(); private final Mat3 angMat = new Mat3();
private int movementX = 0; private int movementForward = 0;
private int movementY = 0; private int movementRight = 0;
private int movementZ = 0; private int movementUp = 0;
private static final boolean I_WANT_TO_THROW_UP = false; private static final boolean I_WANT_TO_THROW_UP = false;
private float shakeParam = 0; private float shakeParam = 0;
@ -81,12 +81,12 @@ public class LayerWorld extends Layer {
renderWorld(); renderWorld();
helper.reset(); helper.reset();
angMat.set().rotateY(-camera.getYaw()); angMat.set().rotateZ(-camera.getYaw());
tmp.set(movementX, 0, movementZ); tmp.set(movementForward, -movementRight, 0);
if (movementX != 0 && movementZ != 0) tmp.normalize(); if (movementForward != 0 && movementRight != 0) tmp.normalize();
angMat.mul_(tmp); // bug in jglm angMat.mul_(tmp); // bug in jglm
tmp.y = movementY; tmp.z = movementUp;
tmp.mul(0.1f); tmp.mul(0.1f);
tmp.sub(velocity); tmp.sub(velocity);
tmp.mul(0.1f); tmp.mul(0.1f);
@ -141,22 +141,22 @@ public class LayerWorld extends Layer {
switch (event.getKey()) { switch (event.getKey()) {
case GLFW.GLFW_KEY_W: case GLFW.GLFW_KEY_W:
movementZ += -1 * multiplier; movementForward += +1 * multiplier;
break; break;
case GLFW.GLFW_KEY_S: case GLFW.GLFW_KEY_S:
movementZ += +1 * multiplier; movementForward += -1 * multiplier;
break; break;
case GLFW.GLFW_KEY_A: case GLFW.GLFW_KEY_A:
movementX += -1 * multiplier; movementRight += -1 * multiplier;
break; break;
case GLFW.GLFW_KEY_D: case GLFW.GLFW_KEY_D:
movementX += +1 * multiplier; movementRight += +1 * multiplier;
break; break;
case GLFW.GLFW_KEY_SPACE: case GLFW.GLFW_KEY_SPACE:
movementY += +1 * multiplier; movementUp += +1 * multiplier;
break; break;
case GLFW.GLFW_KEY_LEFT_SHIFT: case GLFW.GLFW_KEY_LEFT_SHIFT:
movementY += -1 * multiplier; movementUp += -1 * multiplier;
break; break;
case GLFW.GLFW_KEY_ESCAPE: case GLFW.GLFW_KEY_ESCAPE:
@ -190,7 +190,7 @@ public class LayerWorld extends Layer {
if (!flag) return; if (!flag) return;
final float yawScale = 0.002f; final float yawScale = 0.002f;
final float pitchScale = -yawScale; final float pitchScale = yawScale;
camera.turn( camera.turn(
(float) (event.getChangeY() * pitchScale), (float) (event.getChangeY() * pitchScale),

View File

@ -56,8 +56,6 @@ public class WorldRender {
} }
public void render(ShapeRenderHelper renderer) { public void render(ShapeRenderHelper renderer) {
renderer.pushTransform().rotateX(-Math.PI / 2);
for (ChunkRender chunk : getChunks()) { for (ChunkRender chunk : getChunks()) {
chunk.render(renderer); chunk.render(renderer);
} }

View File

@ -58,4 +58,9 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube {
return false; return false;
} }
@Override
public boolean needsOwnRenderable() {
return false;
}
} }

View File

@ -21,8 +21,10 @@ import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.function.Consumer;
import glm.vec._3.Vec3; 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.backend.Usage;
import ru.windcorp.progressia.client.graphics.model.Face; import ru.windcorp.progressia.client.graphics.model.Face;
import ru.windcorp.progressia.client.graphics.model.Faces; 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.ChunkRender;
import ru.windcorp.progressia.client.world.renders.BlockRender; import ru.windcorp.progressia.client.world.renders.BlockRender;
import ru.windcorp.progressia.common.block.BlockFace; import ru.windcorp.progressia.common.block.BlockFace;
import ru.windcorp.progressia.common.world.ChunkData;
public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer { public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
@ -42,122 +43,51 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
public boolean isBlockOpaque(); 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 static final Vec3 COLOR_MULTIPLIER = new Vec3(1, 1, 1);
private final byte[][][] data = new byte[BLOCKS_PER_CHUNK + 1] private final OpaqueCube[][][] data =
[BLOCKS_PER_CHUNK + 1] new OpaqueCube[BLOCKS_PER_CHUNK]
[BLOCKS_PER_CHUNK + 1]; [BLOCKS_PER_CHUNK]
[BLOCKS_PER_CHUNK];
private ChunkRender chunk;
private final Vec3 blockCenter = new Vec3();
@Override @Override
public void startRender(ChunkRender chunk) { public void startRender(ChunkRender chunk) {
this.chunk = chunk; // Do nothing
} }
@Override @Override
public void processBlock(BlockRender block, int x, int y, int z) { public void processBlock(BlockRender block, int x, int y, int z) {
if (!(block instanceof OpaqueCube)) return; if (!(block instanceof OpaqueCube)) return;
OpaqueCube opaqueCube = (OpaqueCube) block; OpaqueCube opaqueCube = (OpaqueCube) block;
addBlock(x, y, z, opaqueCube);
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);
} }
protected void addFace(int x, int y, int z, BlockFace face) { protected void addBlock(int x, int y, int z, OpaqueCube cube) {
if (face == BlockFace.BOTTOM) { data[x][y][z] = cube;
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;
} }
data[x + 1][y + 1][z + 1] ^= 1 << getBit(face); protected OpaqueCube getBlock(Vec3i cursor) {
} return data[cursor.x][cursor.y][cursor.z];
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;
} }
@Override @Override
public Shape endRender() { public Shape endRender() {
Collection<Face> shapeFaces = new ArrayList<>( Collection<Face> shapeFaces = new ArrayList<>(
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 + BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
); );
for (int x = -1; x < ChunkData.BLOCKS_PER_CHUNK; ++x) { Vec3i cursor = new Vec3i();
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) {
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)) { processInnerFaces(block, cursor, shapeFaces::add);
if (face == BlockFace.TOP) { processOuterFaces(block, cursor, shapeFaces::add);
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);
}
} }
} }
} }
@ -169,29 +99,82 @@ public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer {
); );
} }
private Face createFace(int x, int y, int z, BlockFace face) { private void processInnerFaces(
OpaqueCube blockRender = OpaqueCube block,
(OpaqueCube) chunk.getBlock(x, y, z); Vec3i cursor,
Texture texture = blockRender.getTexture(face); 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(), WorldRenderProgram.getDefault(),
texture, texture,
COLOR_MULTIPLIER, COLOR_MULTIPLIER,
blockCenter.set(x, y, z), new Vec3(cursor.x, cursor.y, cursor.z),
face face,
); true
));
}
} }
// TODO refactor private void processOuterFaces(
private static int getBit(BlockFace face) { OpaqueCube block,
if (face == BlockFace.TOP) return 0; Vec3i cursor,
if (face == BlockFace.BOTTOM) return 1; Consumer<Face> output
if (face == BlockFace.NORTH) return 2; ) {
if (face == BlockFace.SOUTH) return 3; for (BlockFace face : BlockFace.getFaces()) {
if (face == BlockFace.WEST) return 4;
if (face == BlockFace.EAST) return 5; Texture texture = block.getTexture(face);
return -1; 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;
} }
} }

View File

@ -26,14 +26,25 @@ public final class BlockFace extends BlockRelation {
BOTTOM = new BlockFace( 0, 0, -1, false), BOTTOM = new BlockFace( 0, 0, -1, false),
NORTH = new BlockFace(+1, 0, 0, true), NORTH = new BlockFace(+1, 0, 0, true),
SOUTH = new BlockFace(-1, 0, 0, false), SOUTH = new BlockFace(-1, 0, 0, false),
WEST = new BlockFace( 0, +1, 0, true), WEST = new BlockFace( 0, +1, 0, false),
EAST = 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); ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST);
public static ImmutableList<BlockFace> getValues() { private static final ImmutableList<BlockFace> PRIMARY_FACES =
return ALL_VALUES; 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 { static {

View File

@ -3,7 +3,7 @@
varying vec3 varyingNormals; varying vec3 varyingNormals;
void applyShading() { 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; vec3 normal = varyingNormals;
float angleCos = dot(normal, light); float angleCos = dot(normal, light);