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 }