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.mesh.meshgen; 7 8 import voxelman.log; 9 import core.time; 10 import std.conv : to; 11 import voxelman.platform.isharedcontext; 12 13 import voxelman.container.buffer; 14 import voxelman.math; 15 import voxelman.geometry; 16 17 import voxelman.world.block; 18 import voxelman.world.blockentity; 19 20 import voxelman.world.block; 21 import voxelman.world.mesh.chunkmesh; 22 import voxelman.world.mesh.extendedchunk; 23 import voxelman.core.config; 24 import voxelman.thread.worker; 25 import voxelman.world.storage; 26 27 28 enum MeshGenTaskType : ubyte 29 { 30 genMesh, 31 unloadMesh 32 } 33 34 struct MeshGenTaskHeader 35 { 36 MeshGenTaskType type; 37 size_t meshGroupId; 38 ChunkWorldPos cwp; 39 } 40 41 //version = DBG_OUT; 42 void meshWorkerThread(shared(Worker)* workerInfo, SeparatedBlockInfoTable blockInfos, BlockEntityInfoTable beInfos) 43 { 44 // reusable buffers 45 Buffer!MeshVertex[3] geometry; // 2 - solid, 1 - semiTransparent 46 47 try 48 { 49 while (workerInfo.needsToRun) 50 { 51 workerInfo.waitForNotify(); 52 53 // receive 54 // MeshGenTaskHeader taskHeader; 55 // ChunkLayerItem[7] blockLayers; 56 // ChunkLayerItem[7] entityLayers; 57 // or 58 // MeshGenTaskHeader taskHeader; 59 // 60 // send 61 // MeshGenTaskHeader taskHeader; 62 // MeshVertex[][2] meshes; 63 // uint[7] blockTimestamps; 64 // uint[7] entityTimestamps; 65 // or 66 // MeshGenTaskHeader taskHeader; 67 if (!workerInfo.taskQueue.empty) 68 { 69 auto taskHeader = workerInfo.taskQueue.popItem!MeshGenTaskHeader(); 70 71 if (taskHeader.type == MeshGenTaskType.genMesh) 72 { 73 auto taskStartTime = MonoTime.currTime; 74 75 // get mesh task. 76 auto blockLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]); 77 auto entityLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]); 78 auto metadataLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]); 79 80 chunkMeshWorker( 81 blockLayers, entityLayers, metadataLayers, 82 blockInfos, beInfos, geometry); 83 84 import std.experimental.allocator; 85 import std.experimental.allocator.mallocator; 86 87 MeshVertex[][2] meshes; 88 meshes[0] = makeArray!MeshVertex(Mallocator.instance, geometry[2].data); // solid geometry 89 meshes[1] = makeArray!MeshVertex(Mallocator.instance, geometry[1].data); // semi-transparent geometry 90 geometry[1].clear(); 91 geometry[2].clear(); 92 93 uint[27] blockTimestamps; 94 uint[27] entityTimestamps; 95 uint[27] metadataTimestamps; 96 foreach(i; 0..27) blockTimestamps[i] = blockLayers[i].timestamp; 97 foreach(i; 0..27) entityTimestamps[i] = entityLayers[i].timestamp; 98 foreach(i; 0..27) metadataTimestamps[i] = metadataLayers[i].timestamp; 99 100 auto duration = MonoTime.currTime - taskStartTime; 101 102 workerInfo.resultQueue.startMessage(); 103 workerInfo.resultQueue.pushMessagePart(taskHeader); 104 workerInfo.resultQueue.pushMessagePart(meshes); 105 workerInfo.resultQueue.pushMessagePart(blockTimestamps); 106 workerInfo.resultQueue.pushMessagePart(entityTimestamps); 107 workerInfo.resultQueue.pushMessagePart(metadataTimestamps); 108 workerInfo.resultQueue.pushMessagePart(duration); 109 workerInfo.resultQueue.endMessage(); 110 } 111 else 112 { 113 // remove mesh task. Resend it to main thread. 114 workerInfo.resultQueue.pushItem(taskHeader); 115 } 116 } 117 } 118 } 119 catch(Throwable t) 120 { 121 infof("%s from mesh worker", t.to!string); 122 throw t; 123 } 124 version(DBG_OUT)infof("Mesh worker stopped"); 125 } 126 127 import voxelman.world.mesh.meshgenerator; 128 129 void chunkMeshWorker( 130 ChunkLayerItem[27] blockLayers, 131 ChunkLayerItem[27] entityLayers, 132 ChunkLayerItem[27] metadataLayers, 133 SeparatedBlockInfoTable blockInfos, 134 BlockEntityInfoTable beInfos, 135 ref Buffer!MeshVertex[3] geometry) 136 { 137 foreach (layer; blockLayers) { 138 assert(layer.type != StorageType.compressedArray, "[MESHING] Data needs to be uncompressed 1"); 139 if (!layer.isUniform) 140 assert(layer.getArray!ubyte.length == BLOCKS_DATA_LENGTH); 141 } 142 foreach (layer; entityLayers) 143 assert(layer.type != StorageType.compressedArray, "[MESHING] Data needs to be uncompressed 2"); 144 145 BlockEntityMap[27] maps; 146 foreach (i, layer; entityLayers) maps[i] = getHashMapFromLayer(layer); 147 148 ExtendedChunk chunk; 149 chunk.create(blockLayers); 150 genGeometry(chunk, entityLayers, metadataLayers, beInfos, blockInfos, geometry); 151 }