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