1 /** 2 Copyright: Copyright (c) 2013-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.core.meshgen; 7 8 import std.experimental.logger; 9 import std.array : Appender; 10 import std.concurrency : Tid, send, receive; 11 import std.conv : to; 12 import std.variant : Variant; 13 import core.atomic : atomicLoad; 14 import core.exception : Throwable; 15 16 import dlib.math.vector : ivec3; 17 18 import voxelman.core.block; 19 import voxelman.core.config; 20 import voxelman.storage.chunk; 21 import voxelman.storage.coordinates; 22 23 24 struct MeshGenResult 25 { 26 ubyte[] meshData; 27 ChunkWorldPos position; 28 } 29 30 void meshWorkerThread(Tid mainTid, immutable(Block*)[] blocks) 31 { 32 try 33 { 34 shared(bool)* isRunning; 35 bool isRunningLocal = true; 36 receive( (shared(bool)* _isRunning){isRunning = _isRunning;} ); 37 38 while (atomicLoad(*isRunning) && isRunningLocal) 39 { 40 receive( 41 (shared(Chunk)* chunk) 42 { 43 //infof("worker: mesh chunk %s", chunk.position); 44 chunkMeshWorker(cast(Chunk*)chunk, (cast(Chunk*)chunk).adjacent, blocks, mainTid); 45 }, 46 (shared(Chunk)* chunk, ushort[2] changedBlocksRange) 47 { 48 //chunkMeshWorker(cast(Chunk*)chunk, (cast(Chunk*)chunk).adjacent, blocks, mainTid); 49 }, 50 (Variant v){isRunningLocal = false;} 51 ); 52 } 53 } 54 catch(Throwable t) 55 { 56 error(t.to!string, " from mesh worker"); 57 throw t; 58 } 59 } 60 61 void chunkMeshWorker(Chunk* chunk, Chunk*[6] adjacent, immutable(Block*)[] blocks, Tid mainThread) 62 in 63 { 64 assert(chunk); 65 assert(!chunk.hasWriter); 66 foreach(a; adjacent) 67 { 68 assert(a !is null); 69 assert(!a.hasWriter); 70 } 71 } 72 body 73 { 74 Appender!(ubyte[]) appender; 75 ubyte bx, by, bz; 76 77 bool isVisibleBlock(uint id) 78 { 79 return blocks[id].isVisible; 80 } 81 82 bool getTransparency(int tx, int ty, int tz, Side side) 83 { 84 ubyte x = cast(ubyte)tx; 85 ubyte y = cast(ubyte)ty; 86 ubyte z = cast(ubyte)tz; 87 88 if(tx == -1) // west 89 return blocks[ adjacent[Side.west].getBlockType(CHUNK_SIZE-1, y, z) ].isSideTransparent(side); 90 else if(tx == CHUNK_SIZE) // east 91 return blocks[ adjacent[Side.east].getBlockType(0, y, z) ].isSideTransparent(side); 92 93 if(ty == -1) // bottom 94 { 95 assert(side == Side.top, to!string(side)); 96 return blocks[ adjacent[Side.bottom].getBlockType(x, CHUNK_SIZE-1, z) ].isSideTransparent(side); 97 } 98 else if(ty == CHUNK_SIZE) // top 99 { 100 return blocks[ adjacent[Side.top].getBlockType(x, 0, z) ].isSideTransparent(side); 101 } 102 103 if(tz == -1) // north 104 return blocks[ adjacent[Side.north].getBlockType(x, y, CHUNK_SIZE-1) ].isSideTransparent(side); 105 else if(tz == CHUNK_SIZE) // south 106 return blocks[ adjacent[Side.south].getBlockType(x, y, 0) ].isSideTransparent(side); 107 108 return blocks[ chunk.getBlockType(x, y, z) ].isSideTransparent(side); 109 } 110 111 // Bit flags of sides to render 112 ubyte sides = 0; 113 // Num of sides to render 114 ubyte sidenum = 0; 115 // Offset to adjacent block 116 byte[3] offset; 117 118 if (chunk.snapshot.blockData.uniform) 119 { 120 foreach (uint index; 0..CHUNK_SIZE_CUBE) 121 { 122 bx = index & CHUNK_SIZE_BITS; 123 by = (index / CHUNK_SIZE_SQR) & CHUNK_SIZE_BITS; 124 bz = (index / CHUNK_SIZE) & CHUNK_SIZE_BITS; 125 sides = 0; 126 sidenum = 0; 127 128 foreach(ubyte side; 0..6) 129 { 130 offset = sideOffsets[cast(Side)side]; 131 132 if(getTransparency(bx+offset[0], by+offset[1], bz+offset[2], cast(Side)oppSide[side])) 133 { 134 sides |= 2^^(side); 135 ++sidenum; 136 } 137 } 138 139 appender ~= blocks[chunk.snapshot.blockData.uniformType] 140 .mesh(bx, by, bz, sides, sidenum); 141 } // foreach 142 } 143 else 144 foreach (uint index, ref ubyte val; chunk.snapshot.blockData.blocks) 145 { 146 if (isVisibleBlock(val)) 147 { 148 bx = index & CHUNK_SIZE_BITS; 149 by = (index / CHUNK_SIZE_SQR) & CHUNK_SIZE_BITS; 150 bz = (index / CHUNK_SIZE) & CHUNK_SIZE_BITS; 151 sides = 0; 152 sidenum = 0; 153 154 foreach(ubyte side; 0..6) 155 { 156 offset = sideOffsets[cast(Side)side]; 157 158 if(getTransparency(bx+offset[0], by+offset[1], bz+offset[2], cast(Side)oppSide[side])) 159 { 160 sides |= 2^^(side); 161 ++sidenum; 162 } 163 } 164 165 appender ~= blocks[val].mesh(bx, by, bz, sides, sidenum); 166 } // if(val != 0) 167 } // foreach 168 169 auto result = cast(immutable(MeshGenResult)*) 170 new MeshGenResult(cast(ubyte[])appender.data, chunk.position); 171 mainThread.send(result); 172 }