1 /** 2 Copyright: Copyright (c) 2016-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.mesh.meshgenerator; 7 8 import voxelman.log; 9 import std.conv : to; 10 11 import voxelman.container.buffer; 12 import voxelman.math; 13 import voxelman.geometry; 14 15 import voxelman.world.block; 16 import voxelman.world.blockentity; 17 import voxelman.world.mesh.chunkmesh; 18 import voxelman.algorithm.arraycopy3d; 19 import voxelman.core.config; 20 import voxelman.thread.worker; 21 import voxelman.world.storage; 22 23 import voxelman.world.mesh.config; 24 import voxelman.world.mesh.utils; 25 import voxelman.world.mesh.extendedchunk; 26 27 void genGeometry(const ref ExtendedChunk chunk, 28 ChunkLayerItem[27] entityLayers, 29 ChunkLayerItem[27] metadataLayers, 30 BlockEntityInfoTable beInfos, 31 SeparatedBlockInfoTable blockInfoTable, 32 ref Buffer!MeshVertex[3] geometry) 33 { 34 //const BlockInfo[] blockInfos = blockInfoTable.blockInfos; 35 foreach (layer; entityLayers) 36 assert(layer.type != StorageType.compressedArray, "[MESHING] Data needs to be uncompressed 2"); 37 38 BlockEntityMap[27] maps; 39 foreach (i, layer; entityLayers) maps[i] = getHashMapFromLayer(layer); 40 41 BlockEntityData getBlockEntity(ushort index, BlockEntityMap map) { 42 ulong* entity = index in map; 43 if (entity is null) return BlockEntityData.init; 44 return BlockEntityData(*entity); 45 } 46 47 BlockShape getEntityShape(BlockId blockId, ushort index) 48 { 49 ushort entityBlockIndex = blockEntityIndexFromBlockId(blockId); 50 auto cb = chunkAndBlockAt27FromExt(index); 51 BlockEntityData data = getBlockEntity(entityBlockIndex, maps[cb.chunk]); 52 auto entityChunkPos = BlockChunkPos(entityBlockIndex); 53 ivec3 blockChunkPos = ivec3(cb.bx, cb.by, cb.bz); 54 ivec3 blockEntityPos = blockChunkPos - entityChunkPos.vector; 55 return beInfos[data.id].blockShape(blockChunkPos, blockEntityPos, data); 56 } 57 58 BlockShape getShape(BlockId blockId, ushort index) 59 { 60 if (isBlockEntity(blockId)) 61 { 62 return getEntityShape(blockId, index); 63 } 64 else 65 { 66 if (blockInfoTable.shapeDependsOnMeta[blockId]) 67 { 68 auto cb = chunkAndBlockAt27FromExt(index); 69 auto blockMetadata = getLayerItemNoncompressed!BlockMetadata(metadataLayers[cb.chunk], BlockChunkIndex(cb.bx, cb.by, cb.bz)); 70 return blockInfoTable.shapeMetaHandler[blockId](blockMetadata); 71 } 72 else 73 { 74 return blockInfoTable.shape[blockId]; 75 } 76 } 77 } 78 79 //pragma(inline, true) 80 ShapeSideMask getSideMask(ushort index, ubyte side) 81 { 82 BlockId blockId = chunk.allBlocks.ptr[index]; 83 return getShape(blockId, index).sideMasks[side]; 84 } 85 86 //pragma(inline, true) 87 bool isSideRendered(size_t index, ubyte side, const ShapeSideMask currentMask) 88 { 89 return blockInfoTable.sideTable.get(currentMask, getSideMask(cast(ushort)index, side)); 90 } 91 92 ubyte checkSideSolidities(const ref ShapeSideMask[6] sideMasks, size_t index) 93 { 94 ubyte sides = 0; 95 96 sides |= isSideRendered(index + sideIndexOffsets[0], 1, sideMasks[0]) << 0; 97 sides |= isSideRendered(index + sideIndexOffsets[1], 0, sideMasks[1]) << 1; 98 sides |= isSideRendered(index + sideIndexOffsets[2], 3, sideMasks[2]) << 2; 99 sides |= isSideRendered(index + sideIndexOffsets[3], 2, sideMasks[3]) << 3; 100 sides |= isSideRendered(index + sideIndexOffsets[4], 5, sideMasks[4]) << 4; 101 sides |= isSideRendered(index + sideIndexOffsets[5], 4, sideMasks[5]) << 5; 102 103 return sides; 104 } 105 106 // assumes that block to the side has lower solidity than current block 107 // 0--3 // corner numbering of face verticies 108 // |\ | 109 // 1--2 110 //pragma(inline, true) 111 ubyte getCorners(size_t index) 112 { 113 BlockId blockId = chunk.allBlocks.ptr[index]; 114 return getShape(blockId, cast(ushort)index).corners; 115 } 116 117 static if (AO_ENABLED) 118 ubyte[4] calcFaceCornerOcclusions(ushort blockIndex, CubeSide side) 119 { 120 int index = blockIndex + sideIndexOffsets[side]; 121 122 ubyte cornersC = getCorners(index); 123 ubyte cornersT = getCorners(index + faceSideIndexOffset[side][0]); 124 ubyte cornersL = getCorners(index + faceSideIndexOffset[side][1]); 125 ubyte cornersB = getCorners(index + faceSideIndexOffset[side][2]); 126 ubyte cornersR = getCorners(index + faceSideIndexOffset[side][3]); 127 ubyte[16] faceCornersToAdjCorners = faceSideCorners4[side]; 128 129 bool getCorner(ubyte corners, ubyte tableIndex) 130 { 131 return (corners & (1 << faceCornersToAdjCorners[tableIndex])) != 0; 132 } 133 134 ubyte result0 = getCorner(cornersT, 1) | getCorner(cornersL, 3) << 1; 135 if (result0 < 3) result0 |= getCorner(getCorners(index + faceSideIndexOffset[side][4]), 2) << 2; 136 result0 |= getCorner(cornersC, 0) << 3; 137 138 ubyte result1 = getCorner(cornersL, 5) | getCorner(cornersB, 7) << 1; 139 if (result1 < 3) result1 |= getCorner(getCorners(index + faceSideIndexOffset[side][5]), 6) << 2; 140 result1 |= getCorner(cornersC, 4) << 3; 141 142 ubyte result2 = getCorner(cornersB, 9) | getCorner(cornersR, 11) << 1; 143 if (result2 < 3) result2 |= getCorner(getCorners(index + faceSideIndexOffset[side][6]), 10) << 2; 144 result2 |= getCorner(cornersC, 8) << 3; 145 146 ubyte result3 = getCorner(cornersR, 13) | getCorner(cornersT, 15) << 1; 147 if (result3 < 3) result3 |= getCorner(getCorners(index + faceSideIndexOffset[side][7]), 14) << 2; 148 result3 |= getCorner(cornersC, 12) << 3; 149 150 return [result0, result1, result2, result3]; 151 } 152 153 static if (!AO_ENABLED) 154 ubyte[4] calcFaceCornerOcclusions(ushort blockIndex, CubeSide side) 155 { 156 return [0,0,0,0]; 157 } 158 159 void meshBlock(BlockId blockId, ushort index, ubvec3 bpos) 160 { 161 const BlockInfo binfo = blockInfoTable.blockInfos[blockId]; 162 if (binfo.isVisible) 163 { 164 auto shape = getShape(blockId, index); 165 ubyte sides = checkSideSolidities(shape.sideMasks, index); 166 167 if ((sides != 0) || shape.hasInternalGeometry) 168 { 169 BlockMetadata blockMetadata; 170 if (binfo.meshDependOnMeta) 171 { 172 auto cb = chunkAndBlockAt27FromExt(cast(ushort)index); 173 blockMetadata = getLayerItemNoncompressed!BlockMetadata(metadataLayers[cb.chunk], BlockChunkIndex(cb.bx, cb.by, cb.bz)); 174 } 175 auto data = BlockMeshingData( 176 &geometry[binfo.solidity], 177 &calcFaceCornerOcclusions, 178 binfo.color, 179 binfo.uv, 180 bpos, 181 sides, 182 index, 183 blockMetadata); 184 binfo.meshHandler(data); 185 } 186 } 187 } 188 189 void meshBlockEntity(BlockId blockId, ushort index, ubvec3 bpos) 190 { 191 ubyte sides = checkSideSolidities(getShape(blockId, index).sideMasks, index); 192 ushort entityBlockIndex = blockEntityIndexFromBlockId(blockId); 193 BlockEntityData data = getBlockEntity(entityBlockIndex, maps[26]); 194 195 // entity chunk pos 196 auto entityChunkPos = BlockChunkPos(entityBlockIndex); 197 198 ivec3 blockChunkPos = ivec3(bpos); 199 ivec3 blockEntityPos = blockChunkPos - entityChunkPos.vector; 200 201 auto entityInfo = beInfos[data.id]; 202 203 auto meshingData = BlockEntityMeshingData( 204 geometry, 205 &calcFaceCornerOcclusions, 206 entityInfo.color, 207 sides, 208 blockChunkPos, 209 blockEntityPos, 210 data, 211 index); 212 213 entityInfo.meshHandler(meshingData); 214 } 215 216 size_t index = extendedChunkIndex(1, 1, 1); 217 218 foreach (ubyte y; 0..CHUNK_SIZE) 219 { 220 foreach (ubyte z; 0..CHUNK_SIZE) 221 { 222 foreach (ubyte x; 0..CHUNK_SIZE) 223 { 224 BlockId blockId = chunk.allBlocks.ptr[index]; 225 ubvec3 bpos = ubvec3(x, y, z); 226 227 if (isBlockEntity(blockId)) 228 { 229 meshBlockEntity(blockId, cast(ushort)index, bpos); 230 } 231 else 232 { 233 meshBlock(blockId, cast(ushort)index, bpos); 234 } 235 236 ++index; 237 } 238 index +=2; 239 } 240 index += EXTENDED_CHUNK_SIZE*2; 241 } 242 } 243 244 struct SingleBlockMesher 245 { 246 Buffer!MeshVertex geometry; 247 248 void meshBlock(const BlockInfo binfo, BlockMetadata blockMetadata) 249 { 250 ubyte[4] calcFaceCornerOcclusions(ushort blockIndex, CubeSide side) 251 { 252 return [0,0,0,0]; 253 } 254 255 auto data = BlockMeshingData( 256 &geometry, 257 &calcFaceCornerOcclusions, 258 binfo.color, 259 binfo.uv, 260 ubvec3(0,0,0), 261 0b111111, 262 0, 263 blockMetadata); 264 binfo.meshHandler(data); 265 } 266 267 void reset() 268 { 269 geometry.clear(); 270 } 271 }