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 }