1 /** 2 Copyright: Copyright (c) 2013-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.world.block.blockinfo; 7 8 import voxelman.log; 9 10 import voxelman.container.buffer; 11 import voxelman.math; 12 import voxelman.geometry; 13 import voxelman.core.config; 14 import voxelman.world.storage; 15 import voxelman.utils.mapping; 16 import voxelman.world.block; 17 import voxelman.world.mesh.chunkmesh; 18 19 20 struct ChunkAndBlockAt 21 { 22 ubyte chunk; 23 // position of block in chunk 24 ubyte bx, by, bz; 25 } 26 27 // 0-5 sides, or 6 if center 28 ChunkAndBlockAt chunkAndBlockAt6(int x, int y, int z) 29 { 30 ubyte bx = cast(ubyte)x; 31 ubyte by = cast(ubyte)y; 32 ubyte bz = cast(ubyte)z; 33 34 if(x == -1) return ChunkAndBlockAt(CubeSide.xneg, CHUNK_SIZE-1, by, bz); 35 else if(x == CHUNK_SIZE) return ChunkAndBlockAt(CubeSide.xpos, 0, by, bz); 36 37 if(y == -1) return ChunkAndBlockAt(CubeSide.yneg, bx, CHUNK_SIZE-1, bz); 38 else if(y == CHUNK_SIZE) return ChunkAndBlockAt(CubeSide.ypos, bx, 0, bz); 39 40 if(z == -1) return ChunkAndBlockAt(CubeSide.zneg, bx, by, CHUNK_SIZE-1); 41 else if(z == CHUNK_SIZE) return ChunkAndBlockAt(CubeSide.zpos, bx, by, 0); 42 43 return ChunkAndBlockAt(26, bx, by, bz); 44 } 45 46 // convert -1..33 -> 0..34 to use as index 47 ubyte[34] position_in_target_chunk = [CHUNK_SIZE-1, // CHUNK_SIZE-1 is in adjacent chunk 48 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 49 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 0]; // 0 is in adjacent chunk 50 51 // 0 chunk in neg direction, 1 this chunk, 1 pos dir 52 ubyte[34] target_chunk = 53 [0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2]; 54 55 ChunkAndBlockAt chunkAndBlockAt27(int x, int y, int z) 56 { 57 ubyte bx = position_in_target_chunk[x+1]; 58 ubyte by = position_in_target_chunk[y+1]; 59 ubyte bz = position_in_target_chunk[z+1]; 60 61 ubyte cx = target_chunk[x+1]; 62 ubyte cy = target_chunk[y+1]; 63 ubyte cz = target_chunk[z+1]; 64 65 ubyte chunk_index = cast(ubyte)(cx + cz * 3 + cy * 9); 66 67 return ChunkAndBlockAt(chunk_index, bx, by, bz); 68 } 69 70 alias BlockUpdateHandler = void delegate(BlockWorldPos bwp); 71 struct BlockMeshingData 72 { 73 Buffer!MeshVertex* buffer; 74 ubyte[4] delegate(ushort blockIndex, CubeSide side) occlusionHandler; 75 ubvec3 color; 76 ubyte[2] uv; 77 ubvec3 chunkPos; 78 ubyte sides; 79 ushort blockIndex; 80 BlockMetadata metadata; 81 } 82 alias MeshHandler = void function(BlockMeshingData); 83 alias ShapeMetaHandler = BlockShape function(BlockMetadata); 84 alias RotationHandler = void function(ref BlockMetadata, ubyte, CubeSide); 85 void makeNullMesh(BlockMeshingData) {} 86 87 alias SideSolidityHandler = Solidity function(CubeSide); 88 Solidity transparentSideSolidity(CubeSide) { return Solidity.transparent; } 89 Solidity semitransparentSideSolidity(CubeSide) { return Solidity.semiTransparent; } 90 Solidity solidSideSolidity(CubeSide) { return Solidity.solid; } 91 92 // solidity number increases with solidity 93 enum Solidity : ubyte 94 { 95 transparent, 96 semiTransparent, 97 solid, 98 } 99 100 bool isMoreSolidThan(Solidity first, Solidity second) 101 { 102 return first > second; 103 } 104 105 struct BlockInfo 106 { 107 string name; 108 MeshHandler meshHandler = &makeNullMesh; 109 ubvec3 color; 110 bool isVisible = true; 111 Solidity solidity = Solidity.solid; 112 BlockShape shape = fullShape; 113 ShapeMetaHandler shapeMetaHandler; 114 RotationHandler rotationHandler; 115 bool shapeDependsOnMeta = false; 116 bool meshDependOnMeta = false; 117 //irect atlasRect; 118 ubyte[2] uv; 119 size_t id; 120 } 121 122 BlockInfo entityBlock = BlockInfo("Entity", &makeColoredFullBlockMesh); 123 struct BlockInfoTable 124 { 125 immutable(BlockInfo)[] blockInfos; 126 SideIntersectionTable sideTable; 127 128 size_t length() {return blockInfos.length; } 129 130 BlockInfo opIndex(BlockId blockId) { 131 if (blockId >= blockInfos.length) 132 return entityBlock; 133 return blockInfos[blockId]; 134 } 135 } 136 137 struct SeparatedBlockInfoTable 138 { 139 this(BlockInfoTable infoTable) 140 { 141 sideTable = infoTable.sideTable; 142 shape.length = infoTable.length; 143 corners.length = infoTable.length; 144 hasGeometry.length = infoTable.length; 145 hasInternalGeometry.length = infoTable.length; 146 sideMasks.length = infoTable.length; 147 color.length = infoTable.length; 148 meshHandler.length = infoTable.length; 149 shapeMetaHandler.length = infoTable.length; 150 shapeDependsOnMeta.length = infoTable.length; 151 meshDependOnMeta.length = infoTable.length; 152 153 foreach(i, binfo; infoTable.blockInfos) 154 { 155 shape[i] = binfo.shape; 156 corners[i] = binfo.shape.corners; 157 hasGeometry[i] = binfo.shape.hasGeometry; 158 hasInternalGeometry[i] = binfo.shape.hasInternalGeometry; 159 sideMasks[i] = binfo.shape.sideMasks; 160 color[i] = binfo.color; 161 meshHandler[i] = binfo.meshHandler; 162 shapeMetaHandler[i] = binfo.shapeMetaHandler; 163 shapeDependsOnMeta[i] = binfo.shapeDependsOnMeta; 164 meshDependOnMeta[i] = binfo.meshDependOnMeta; 165 } 166 167 blockInfos = infoTable.blockInfos; 168 } 169 170 immutable(BlockInfo)[] blockInfos; 171 SideIntersectionTable sideTable; 172 BlockShape[] shape; 173 ubyte[] corners; 174 bool[] hasGeometry; 175 bool[] hasInternalGeometry; 176 bool[] shapeDependsOnMeta; 177 bool[] meshDependOnMeta; 178 ShapeSideMask[6][] sideMasks; 179 ubvec3[] color; 180 MeshHandler[] meshHandler; 181 ShapeMetaHandler[] shapeMetaHandler; 182 } 183 184 /// Returned when registering block. 185 /// Use this to set block properties. 186 struct BlockInfoSetter 187 { 188 private Mapping!(BlockInfo)* mapping; 189 private size_t blockId; 190 private ref BlockInfo info() {return (*mapping)[blockId]; } 191 192 ref BlockInfoSetter meshHandler(MeshHandler val) { info.meshHandler = val; return this; } 193 ref BlockInfoSetter color(ubyte[3] color ...) { info.color = ubvec3(color); return this; } 194 ref BlockInfoSetter colorHex(uint hex) { info.color = ubvec3((hex>>16)&0xFF,(hex>>8)&0xFF,hex&0xFF); return this; } 195 ref BlockInfoSetter isVisible(bool val) { info.isVisible = val; return this; } 196 ref BlockInfoSetter solidity(Solidity val) { info.solidity = val; return this; } 197 ref BlockInfoSetter blockShape(BlockShape val) { info.shape = val; return this; } 198 ref BlockInfoSetter shapeMetaHandler(ShapeMetaHandler val) { 199 info.shapeMetaHandler = val; 200 info.shapeDependsOnMeta = true; 201 return this; 202 } 203 //ref BlockInfoSetter shapeDependsOnMeta(bool val) { info.shapeDependsOnMeta = val; return this; } 204 ref BlockInfoSetter meshDependOnMeta(bool val) { info.meshDependOnMeta = val; return this; } 205 ref BlockInfoSetter rotationHandler(RotationHandler val) { info.rotationHandler = val; return this; } 206 } 207 208 import voxelman.world.mesh.blockmeshers.full; 209 import voxelman.world.mesh.blockmeshers.slope; 210 211 void regBaseBlocks(BlockInfoSetter delegate(string name) regBlock) 212 { 213 regBlock("unknown").color(0,0,0).isVisible(false).solidity(Solidity.solid).meshHandler(&makeNullMesh).blockShape(unknownShape); 214 regBlock("air").color(0,0,0).isVisible(false).solidity(Solidity.transparent).meshHandler(&makeNullMesh).blockShape(emptyShape); 215 regBlock("grass").colorHex(0x01A611).meshHandler(&makeColoredFullBlockMesh); 216 regBlock("dirt").colorHex(0x835929).meshHandler(&makeColoredFullBlockMesh); 217 regBlock("stone").colorHex(0x8B8D7A).meshHandler(&makeColoredFullBlockMesh); 218 regBlock("sand").colorHex(0xA68117).meshHandler(&makeColoredFullBlockMesh); 219 regBlock("water").colorHex(0x0055AA).meshHandler(&makeColoredFullBlockMesh).solidity(Solidity.semiTransparent).blockShape(waterShape); 220 regBlock("lava").colorHex(0xFF6920).meshHandler(&makeColoredFullBlockMesh); 221 regBlock("snow").colorHex(0xDBECF6).meshHandler(&makeColoredFullBlockMesh); 222 regBlock("slope").colorHex(0x857FFF).meshHandler(&makeColoredSlopeBlockMesh).shapeMetaHandler(&slopeShapeFromMeta) 223 .meshDependOnMeta(true).rotationHandler(&slopeRotationHandler); 224 } 225 226 void setSideTable(ref SideIntersectionTable sideTable) 227 { 228 sideTable.set(ShapeSideMask.full, ShapeSideMask.empty); 229 sideTable.set(ShapeSideMask.water, ShapeSideMask.empty); 230 sideTable.set(ShapeSideMask.full, ShapeSideMask.water); 231 232 sideTable.set(ShapeSideMask.water, ShapeSideMask.slope0); 233 sideTable.set(ShapeSideMask.full, ShapeSideMask.slope0); 234 sideTable.set(ShapeSideMask.water, ShapeSideMask.slope1); 235 sideTable.set(ShapeSideMask.full, ShapeSideMask.slope1); 236 sideTable.set(ShapeSideMask.water, ShapeSideMask.slope2); 237 sideTable.set(ShapeSideMask.full, ShapeSideMask.slope2); 238 sideTable.set(ShapeSideMask.water, ShapeSideMask.slope3); 239 sideTable.set(ShapeSideMask.full, ShapeSideMask.slope3); 240 241 sideTable.set(ShapeSideMask.slope0, ShapeSideMask.slope0); 242 sideTable.set(ShapeSideMask.slope0, ShapeSideMask.slope1); 243 sideTable.set(ShapeSideMask.slope0, ShapeSideMask.slope2); 244 sideTable.set(ShapeSideMask.slope0, ShapeSideMask.empty); 245 sideTable.set(ShapeSideMask.slope0, ShapeSideMask.water); 246 247 sideTable.set(ShapeSideMask.slope1, ShapeSideMask.slope0); 248 sideTable.set(ShapeSideMask.slope1, ShapeSideMask.slope1); 249 sideTable.set(ShapeSideMask.slope1, ShapeSideMask.slope3); 250 sideTable.set(ShapeSideMask.slope1, ShapeSideMask.empty); 251 sideTable.set(ShapeSideMask.slope1, ShapeSideMask.water); 252 253 sideTable.set(ShapeSideMask.slope2, ShapeSideMask.slope0); 254 sideTable.set(ShapeSideMask.slope2, ShapeSideMask.slope2); 255 sideTable.set(ShapeSideMask.slope2, ShapeSideMask.slope3); 256 sideTable.set(ShapeSideMask.slope2, ShapeSideMask.empty); 257 sideTable.set(ShapeSideMask.slope2, ShapeSideMask.water); 258 259 sideTable.set(ShapeSideMask.slope3, ShapeSideMask.slope1); 260 sideTable.set(ShapeSideMask.slope3, ShapeSideMask.slope2); 261 sideTable.set(ShapeSideMask.slope3, ShapeSideMask.slope3); 262 sideTable.set(ShapeSideMask.slope3, ShapeSideMask.empty); 263 sideTable.set(ShapeSideMask.slope3, ShapeSideMask.water); 264 } 265 266 void slopeRotationHandler(ref BlockMetadata meta, ubyte rotation, CubeSide side) 267 { 268 import voxelman.world.mesh.tables.slope : slopeSideRotations; 269 meta = slopeSideRotations[side][rotation]; 270 }