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