Skip to content

Commit 0ac374a

Browse files
committed
Add stone slab
1 parent c5fa405 commit 0ac374a

File tree

13 files changed

+161
-22
lines changed

13 files changed

+161
-22
lines changed

modules/freeworld.client/src/main/java/freeworld/client/Freeworld.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public final class Freeworld implements AutoCloseable {
8888
BlockTypes.STONE,
8989
BlockTypes.DIRT,
9090
BlockTypes.GRASS_BLOCK,
91-
BlockTypes.AIR,
91+
BlockTypes.STONE_SLAB,
9292
BlockTypes.AIR,
9393
BlockTypes.AIR,
9494
BlockTypes.AIR,

modules/freeworld.client/src/main/java/freeworld/client/render/model/block/BlockModelManager.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
package freeworld.client.render.model.block;
1212

13-
import freeworld.client.render.texture.TextureAtlas;
13+
import freeworld.client.render.texture.Texture;
1414
import freeworld.core.Identifier;
15-
import freeworld.core.registry.Registries;
1615
import freeworld.core.registry.DefaultedRegistry;
16+
import freeworld.core.registry.Registries;
1717
import freeworld.core.registry.Registry;
1818
import freeworld.world.block.BlockType;
1919
import freeworld.world.block.BlockTypes;
@@ -61,11 +61,12 @@ public void register(BlockType blockType, BlockModel blockModel) {
6161
}
6262

6363
public void bootstrap() {
64-
register(TextureAtlas.MISSING, missing());
64+
register(Texture.MISSING, missing());
6565
register(BlockTypes.AIR, empty());
6666
register(BlockTypes.GRASS_BLOCK, new CubeAllBlockModel(Identifier.ofBuiltin("block/grass_block")));
6767
register(BlockTypes.DIRT, new CubeAllBlockModel(Identifier.ofBuiltin("block/dirt")));
6868
register(BlockTypes.STONE, new CubeAllBlockModel(Identifier.ofBuiltin("block/stone")));
69+
register(BlockTypes.STONE_SLAB, new SlabBlockModel(Identifier.ofBuiltin("block/stone"), Identifier.ofBuiltin("block/stone"), Identifier.ofBuiltin("block/stone")));
6970
}
7071

7172
public BlockModel get(Identifier identifier) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* freeworld - 3D sandbox game
3+
* Copyright (C) 2024 XenFork Union
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation;
8+
* only version 2.1 of the License.
9+
*/
10+
11+
package freeworld.client.render.model.block;
12+
13+
import freeworld.client.util.MapBuilder;
14+
import freeworld.core.Identifier;
15+
import freeworld.core.ModelResourcePath;
16+
import freeworld.math.Vector2f;
17+
import freeworld.math.Vector3f;
18+
import freeworld.util.Direction;
19+
20+
import java.util.List;
21+
import java.util.Map;
22+
23+
/**
24+
* @author squid233
25+
* @since 0.1.0
26+
*/
27+
public final class SlabBlockModel implements BlockModel {
28+
private static final Identifier TOP = Identifier.ofBuiltin("top");
29+
private static final Identifier SIDE = Identifier.ofBuiltin("side");
30+
private static final Identifier BOTTOM = Identifier.ofBuiltin("bottom");
31+
private static final ModelResourcePath TOP_MRP = new ModelResourcePath(ModelResourcePath.Type.VARIABLE, TOP);
32+
private static final ModelResourcePath SIDE_MRP = new ModelResourcePath(ModelResourcePath.Type.VARIABLE, SIDE);
33+
private static final ModelResourcePath BOTTOM_MRP = new ModelResourcePath(ModelResourcePath.Type.VARIABLE, BOTTOM);
34+
private static final List<BlockModelPart> LIST = List.of(new BlockModelPart(
35+
Vector3f.ZERO,
36+
new Vector3f(1.0f, 0.5f, 1.0f),
37+
new MapBuilder<Direction, BlockModelFace>()
38+
.entry(Direction.WEST, new BlockModelFace(new Vector2f(0.0f, 0.5f), new Vector2f(1.0f), SIDE_MRP, Direction.WEST))
39+
.entry(Direction.EAST, new BlockModelFace(new Vector2f(0.0f, 0.5f), new Vector2f(1.0f), SIDE_MRP, Direction.EAST))
40+
.entry(Direction.DOWN, new BlockModelFace(Vector2f.ZERO, new Vector2f(1.0f), BOTTOM_MRP, Direction.DOWN))
41+
.entry(Direction.UP, new BlockModelFace(Vector2f.ZERO, new Vector2f(1.0f), TOP_MRP, null))
42+
.entry(Direction.NORTH, new BlockModelFace(new Vector2f(0.0f, 0.5f), new Vector2f(1.0f), SIDE_MRP, Direction.NORTH))
43+
.entry(Direction.SOUTH, new BlockModelFace(new Vector2f(0.0f, 0.5f), new Vector2f(1.0f), SIDE_MRP, Direction.SOUTH))
44+
.build()
45+
));
46+
private final Map<Identifier, Identifier> textureDef;
47+
48+
public SlabBlockModel(Identifier topTexture, Identifier sideTexture, Identifier bottomTexture) {
49+
this.textureDef = Map.of(TOP, topTexture, SIDE, sideTexture, BOTTOM, bottomTexture);
50+
}
51+
52+
@Override
53+
public Map<Identifier, Identifier> textureDefinitions() {
54+
return textureDef;
55+
}
56+
57+
@Override
58+
public List<BlockModelPart> parts() {
59+
return LIST;
60+
}
61+
}

modules/freeworld.client/src/main/java/freeworld/client/render/texture/Texture.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ protected Texture(int id, int width, int height, int mipmapLevel) {
4343
public static Texture load(GLStateMgr gl, Identifier identifier) {
4444
try (Arena arena = Arena.ofConfined()) {
4545
final String path = identifier.toResourcePath(Identifier.ROOT_ASSETS, Identifier.RES_TEXTURE, Identifier.EXT_PNG);
46-
final NativeImage image = NativeImage.load(arena, path);
47-
if (image.failed() && !MISSING.equals(identifier)) {
46+
boolean missing = MISSING.equals(identifier);
47+
final NativeImage image = missing ? NativeImage.fail() : NativeImage.load(arena, path);
48+
if (image.failed() && !missing) {
4849
logger.error("Failed to load texture {}", identifier);
4950
}
5051
final int width = image.width();

modules/freeworld.client/src/main/java/freeworld/client/render/texture/TextureAtlas.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ public static TextureAtlas load(GLStateMgr gl, List<Identifier> identifierList,
4949
try (Arena arena = Arena.ofConfined()) {
5050
final Map<Identifier, NativeImage> imageMap = HashMap.newHashMap(numIds);
5151
identifierList.forEach(identifier -> {
52-
final NativeImage load = NativeImage.load(arena, identifier.toResourcePath(Identifier.ROOT_ASSETS, Identifier.RES_TEXTURE, Identifier.EXT_PNG));
52+
boolean missing = MISSING.equals(identifier);
53+
final NativeImage load = missing ?
54+
NativeImage.fail() :
55+
NativeImage.load(arena, identifier.toResourcePath(Identifier.ROOT_ASSETS, Identifier.RES_TEXTURE, Identifier.EXT_PNG));
5356
imageMap.put(identifier, load);
54-
if (load.failed() && !MISSING.equals(identifier)) {
57+
if (load.failed() && !missing) {
5558
logger.error("Failed to load texture {}", identifier);
5659
}
5760
});

modules/freeworld.client/src/main/java/freeworld/client/render/world/BlockRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void renderBlockModel(VertexBuilder builder, BlockModel model, Matrix4f m
6464
final Vector3f to = part.to().add(x, y, z);
6565
for (var e : part.faces().entrySet()) {
6666
final BlockModelFace face = e.getValue();
67-
if (face != null && !shouldCullFace.test(face.cullFace())) {
67+
if (face != null && (face.cullFace() == null || !shouldCullFace.test(face.cullFace()))) {
6868
final ModelResourcePath path = face.texture();
6969
final TextureRegion region = texture.getRegion(switch (path.type()) {
7070
case DIRECT -> path.identifier();

modules/freeworld.client/src/main/java/freeworld/client/render/world/ChunkCompiler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ public static ChunkVertexData compile(
5757
Vector3i abs = ChunkPos.relativeToAbsolute(chunkPos, nPos);
5858
final boolean shouldRender =
5959
(chunk.isInBound(nPos.x(), nPos.y(), nPos.z()) &&
60-
chunk.getBlockType(nPos.x(), nPos.y(), nPos.z()).nonOpaque()) ||
60+
chunk.getBlockType(nPos.x(), nPos.y(), nPos.z()).hasSidedTransparency()) ||
6161
(chunk.world().isBlockLoaded(abs.x(), abs.y(), abs.z()) &&
62-
chunk.world().getBlockType(abs.x(), abs.y(), abs.z()).nonOpaque()) ||
62+
chunk.world().getBlockType(abs.x(), abs.y(), abs.z()).hasSidedTransparency()) ||
6363
!chunk.world().isBlockLoaded(abs.x(), abs.y(), abs.z()) /* TODO: add method world::tryLoading() */;
6464
return !shouldRender;
6565
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* freeworld - 3D sandbox game
3+
* Copyright (C) 2024 XenFork Union
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation;
8+
* only version 2.1 of the License.
9+
*/
10+
11+
package freeworld.client.util;
12+
13+
import java.util.Collections;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
17+
/**
18+
* @author squid233
19+
* @since 0.1.0
20+
*/
21+
public final class MapBuilder<K, V> {
22+
private final Map<K, V> map = new HashMap<>();
23+
24+
public MapBuilder<K, V> entry(K key, V value) {
25+
map.put(key, value);
26+
return this;
27+
}
28+
29+
public Map<K, V> build() {
30+
return Collections.unmodifiableMap(map);
31+
}
32+
}

modules/freeworld.core/src/main/java/freeworld/util/shape/VoxelShape.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ static VoxelShape fullCube() {
3131
return SingleVoxelShape.FULL_CUBE;
3232
}
3333

34+
static VoxelShape cuboid(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
35+
return new SingleVoxelShape(new AABBox(minX, minY, minZ, maxX, maxY, maxZ));
36+
}
37+
3438
HitResult rayCast(Vector3d origin, Vector3d dir);
3539

3640
List<AABBox> toBoxes();

modules/freeworld.core/src/main/java/freeworld/world/block/AirBlockType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public AirBlockType(Settings settings) {
2121
super(settings);
2222
}
2323

24+
@Override
25+
public boolean hasSidedTransparency() {
26+
return true;
27+
}
28+
2429
@Override
2530
public VoxelShape outlineShape() {
2631
return VoxelShape.empty();

modules/freeworld.core/src/main/java/freeworld/world/block/BlockType.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,41 +18,37 @@
1818
*/
1919
public class BlockType { // must be an identity class
2020
private final boolean air;
21-
private final boolean nonOpaque;
2221

2322
public BlockType(Settings settings) {
2423
this.air = settings.air;
25-
this.nonOpaque = settings.nonOpaque;
2624
}
2725

2826
public static final class Settings {
2927
private boolean air = false;
30-
private boolean nonOpaque = false;
3128

3229
public Settings air() {
3330
this.air = true;
3431
return this;
3532
}
33+
}
3634

37-
public Settings nonOpaque() {
38-
this.nonOpaque = true;
39-
return this;
40-
}
35+
public static VoxelShape createCuboidShape(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
36+
return VoxelShape.cuboid(minX / 16.0, minY / 16.0, minZ / 16.0, maxX / 16.0, maxY / 16.0, maxZ / 16.0);
4137
}
4238

4339
public boolean air() {
4440
return air;
4541
}
4642

47-
public boolean nonOpaque() {
48-
return nonOpaque;
43+
public boolean hasSidedTransparency() {
44+
return false;
4945
}
5046

5147
public VoxelShape outlineShape() {
5248
return VoxelShape.fullCube();
5349
}
5450

5551
public VoxelShape collisionShape() {
56-
return VoxelShape.fullCube();
52+
return outlineShape();
5753
}
5854
}

modules/freeworld.core/src/main/java/freeworld/world/block/BlockTypes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
* @since 0.1.0
2020
*/
2121
public final class BlockTypes {
22-
public static final BlockType AIR = register("air", new AirBlockType(new BlockType.Settings().air().nonOpaque()));
22+
public static final BlockType AIR = register("air", new AirBlockType(new BlockType.Settings().air()));
2323
public static final BlockType GRASS_BLOCK = register("grass_block", new BlockType(new BlockType.Settings()));
2424
public static final BlockType DIRT = register("dirt", new BlockType(new BlockType.Settings()));
2525
public static final BlockType STONE = register("stone", new BlockType(new BlockType.Settings()));
26+
public static final BlockType STONE_SLAB = register("stone_slab", new SlabBlockType(new BlockType.Settings()));
2627

2728
private BlockTypes() {
2829
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* freeworld - 3D sandbox game
3+
* Copyright (C) 2024 XenFork Union
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation;
8+
* only version 2.1 of the License.
9+
*/
10+
11+
package freeworld.world.block;
12+
13+
import freeworld.util.shape.VoxelShape;
14+
15+
/**
16+
* @author squid233
17+
* @since 0.1.0
18+
*/
19+
public class SlabBlockType extends BlockType {
20+
private static final VoxelShape SHAPE = createCuboidShape(0.0, 0.0, 0.0, 16.0, 8.0, 16.0);
21+
22+
public SlabBlockType(Settings settings) {
23+
super(settings);
24+
}
25+
26+
@Override
27+
public boolean hasSidedTransparency() {
28+
return true;
29+
}
30+
31+
@Override
32+
public VoxelShape outlineShape() {
33+
return SHAPE;
34+
}
35+
}

0 commit comments

Comments
 (0)