1 /*
2     Copyright (c) 2009 NetAllied Systems GmbH
3 
4     This file is part of dae23ds.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #include "dae23dsStableHeaders.h"
12 #include "DAE23dsMeshBase.h"
13 
14 #include "Commonitoa.h"
15 
16 
17 namespace DAE23ds
18 {
19 
20 	//------------------------------
MeshBase(Writer * writer3ds,const Writer::MeshData & meshData)21 	MeshBase::MeshBase( Writer* writer3ds, const Writer::MeshData& meshData )
22 		: BaseWriter(writer3ds)
23 		, mMeshData(meshData)
24 		, mGeometryMaterialBindingSet( Writer::compare )
25 	{
26 	}
27 
MeshBase(Writer * writer3ds)28 	MeshBase::MeshBase( Writer* writer3ds )
29 		: BaseWriter(writer3ds)
30 		, mGeometryMaterialBindingSet( Writer::compare )
31 	{
32 		mMeshData.positionsCount = 0;
33 		mMeshData.trianglesCount = 0;
34 	}
35 
36 	//------------------------------
~MeshBase()37 	MeshBase::~MeshBase()
38 	{
39 
40 	}
41 
42 
43 	//------------------------------
handle()44 	bool MeshBase::handle()
45 	{
46 		const COLLADAFW::UniqueId& meshUniqueId = mMeshData.meshUniqueId;
47 		const Writer::GeometryUniqueIdInstanceGeometryInfoMap& instanceGeometryMap = getGeometryUniqueIdInstanceGeometryInfoMap();
48 		Writer::GeometryUniqueIdInstanceGeometryInfoMap::const_iterator lowerBound = instanceGeometryMap.lower_bound(meshUniqueId);
49 		Writer::GeometryUniqueIdInstanceGeometryInfoMap::const_iterator upperBound = instanceGeometryMap.upper_bound(meshUniqueId);
50 
51 		for ( Writer::GeometryUniqueIdInstanceGeometryInfoMap::const_iterator it = lowerBound; it != upperBound; ++it)
52 		{
53 			const Writer::InstanceGeometryInfo& instanceGeometryInfo = it->second;
54 
55 			handleMesh(instanceGeometryInfo);
56 		}
57 
58 		return true;
59 	}
60 
61 	//------------------------------
handleMesh(const Writer::InstanceGeometryInfo & instanceGeometryInfo)62 	bool MeshBase::handleMesh(const Writer::InstanceGeometryInfo& instanceGeometryInfo)
63 	{
64 		const COLLADAFW::InstanceGeometry* instanceGeometry = instanceGeometryInfo.fwInstanceGeometry;
65 
66 		Writer::GeometryMaterialBinding geometryMaterialBinding;
67 		geometryMaterialBinding.fwInstanceGeometry = instanceGeometry;
68 
69 		const COLLADAFW::InstanceGeometry* alreadyUsingInstance = 0;
70 		// check if the mesh with the instanceGeometrys geometryMaterialBinding has already been handled
71 		Writer::GeometryMaterialBindingSet::const_iterator it = mGeometryMaterialBindingSet.find(geometryMaterialBinding);
72 		if ( it == mGeometryMaterialBindingSet.end() )
73 		{
74 			// it has not been handle. Add to set and handle
75 			mGeometryMaterialBindingSet.insert(geometryMaterialBinding);
76 		}
77 		else
78 		{
79 			alreadyUsingInstance = (*it).fwInstanceGeometry;
80 		}
81 
82 		size_t verticesCount = mMeshData.positionsCount / 3;
83 		if ( verticesCount > MAX_INDEX_COUNT )
84 		{
85 
86 			return handleMeshIntoMultipleObjects(instanceGeometryInfo, alreadyUsingInstance );;
87 		}
88 		else
89 		{
90 			return handleMeshIntoOneObject( instanceGeometryInfo, alreadyUsingInstance );
91 		}
92 	}
93 
calculateBlockCountAndRemainingTriangles(size_t trianglesCount,ChunkLength & remainingTriangles,ChunkLength & blockCount,ChunkLength & fullBlockCount)94 	void MeshBase::calculateBlockCountAndRemainingTriangles( size_t trianglesCount, ChunkLength&  remainingTriangles, ChunkLength& blockCount, ChunkLength& fullBlockCount)
95 	{
96 		fullBlockCount = (ChunkLength)(trianglesCount / MAX_TRIANGLES_PER_BLOCK);
97 		remainingTriangles = (ChunkLength)(trianglesCount - fullBlockCount*MAX_TRIANGLES_PER_BLOCK);
98 
99 		blockCount = fullBlockCount + (remainingTriangles == 0 ? 0 : 1);
100 	}
101 
102 	//------------------------------
handleMeshIntoMultipleObjects(const Writer::InstanceGeometryInfo & instanceGeometryInfo,const COLLADAFW::InstanceGeometry * alreadyUsingInstance)103 	bool MeshBase::handleMeshIntoMultipleObjects( const Writer::InstanceGeometryInfo& instanceGeometryInfo, const COLLADAFW::InstanceGeometry* alreadyUsingInstance)
104 	{
105 		const COLLADAFW::InstanceGeometry* instanceGeometry = instanceGeometryInfo.fwInstanceGeometry;
106 		const COLLADAFW::MaterialBindingArray& materialBindings = instanceGeometry->getMaterialBindings();
107 
108 		size_t trianglesCount = calculateTrianglesCount();
109 
110 		ChunkLength remainingTriangles;
111 		ChunkLength blockCount;
112 		ChunkLength fullBlockCount;
113 
114 		calculateBlockCountAndRemainingTriangles( trianglesCount, remainingTriangles, blockCount, fullBlockCount );
115 
116 		ChunkLength verticesLength = calculateTotalVerticesLengthMultiObject(trianglesCount, blockCount);
117 
118 //		ChunkLength materialNamesLength = calculateMaterialNamesLength(materialBindings);
119 
120 		ChunkLength facesMaterialsLength = calculateFacesMaterialsLength(MAX_TRIANGLES_PER_BLOCK, materialBindings);
121 
122 		ChunkLength remainderFacesMaterialsLength = calculateFacesMaterialsLength(remainingTriangles, materialBindings);
123 
124 
125 		ChunkLength facesDescriptionLength = calculateFacesDescriptionLengthMultiObject(trianglesCount, blockCount, facesMaterialsLength, remainderFacesMaterialsLength, fullBlockCount);
126 
127 		// vertices  and faces description plus empty chunk for each block
128 		ChunkLength triangularMeshesLength = verticesLength + facesDescriptionLength+ (EMPTY_CHUNK_LENGTH + TRI_LOCAL_LENGTH)*blockCount;
129 
130 		ChunkLength editObjectLength = calculateTotalObjectLengthMultiObject(triangularMeshesLength, blockCount);
131 
132 		// triangle mesh
133 		//plus plus empty chunk
134 		ChunkLength edit3DSLength = editObjectLength + EMPTY_CHUNK_LENGTH;
135 
136 		// add mesh version size
137 		edit3DSLength += MESH_VERSION_CHUNK_LENGTH;
138 
139 		// edit 3ds plus plus empty chunk
140 		ChunkLength mainLength = edit3DSLength + EMPTY_CHUNK_LENGTH;
141 
142 		// add M3D3DS_VERSION version size
143 		mainLength += M3D_VERSION_CHUNK_LENGTH;
144 
145 		WriteMeshIntoMultipleObjectsData data;
146 		data.editObjectLength = editObjectLength;
147 		data.fullBlocksCount = fullBlockCount;
148 		data.remainingTriangles = remainingTriangles;
149 
150 		return writeMeshIntoMultipleObjects( instanceGeometryInfo, data, alreadyUsingInstance );
151 	}
152 
153 	//------------------------------
handleMeshIntoOneObject(const Writer::InstanceGeometryInfo & instanceGeometryInfo,const COLLADAFW::InstanceGeometry * alreadyUsingInstance)154 	bool MeshBase::handleMeshIntoOneObject( const Writer::InstanceGeometryInfo& instanceGeometryInfo, const COLLADAFW::InstanceGeometry* alreadyUsingInstance)
155 	{
156 		const COLLADAFW::InstanceGeometry* instanceGeometry = instanceGeometryInfo.fwInstanceGeometry;
157 		const COLLADAFW::MaterialBindingArray& materialBindings = instanceGeometry->getMaterialBindings();
158 
159 		CountType trianglesCount = (CountType)calculateTrianglesCount();
160 
161 		ChunkLength verticesLength = calculateVerticesLength();
162 
163 //		ChunkLength materialNamesLength = calculateMaterialNamesLength(materialBindings);
164 
165 		ChunkLength facesMaterialsLength = calculateFacesMaterialsLength(trianglesCount, materialBindings);
166 
167 		ChunkLength facesDescriptionLength = calculateFacesDescriptionLength(trianglesCount, facesMaterialsLength);
168 
169 		// vertices  and faces description plus empty chunk
170 		ChunkLength triangularMeshLength = verticesLength + facesDescriptionLength+ EMPTY_CHUNK_LENGTH + TRI_LOCAL_LENGTH;
171 
172 		ChunkLength editObjectLength = calculateObjectLength(triangularMeshLength);
173 
174 		WriteMeshIntoOneObject data;
175 		data.editObjectLength = editObjectLength;
176 		data.facesDescriptionLength = facesDescriptionLength;
177 		data.trianglesCount = trianglesCount;
178 		data.triangularMeshLength = triangularMeshLength;
179 		data.verticesLength = verticesLength;
180 
181 		return writeMeshIntoOneObject( instanceGeometryInfo, data, alreadyUsingInstance );
182 	}
183 
184 	//------------------------------
calculateVerticesLength()185 	ChunkLength MeshBase::calculateVerticesLength()
186 	{
187 		// size of empty chunk
188 		// size of the vertex count + size of the floats
189 		return calculateVerticesLength((ChunkLength)(mMeshData.positionsCount));
190 	}
191 
192 	//------------------------------
calculateVerticesLength(ChunkLength verticesCount_times3)193 	ChunkLength MeshBase::calculateVerticesLength(ChunkLength verticesCount_times3)
194 	{
195 		// size of empty chunk
196 		// size of the vertex count + size of the floats
197 		return EMPTY_CHUNK_LENGTH + sizeof(CountType) + verticesCount_times3 * (ChunkLength)sizeof(float);
198 	}
199 
200 	//------------------------------
calculateTotalVerticesLengthMultiObject(size_t trianglesCount,ChunkLength blockCount)201 	ChunkLength MeshBase::calculateTotalVerticesLengthMultiObject( size_t trianglesCount, ChunkLength blockCount )
202 	{
203 
204 		// size of empty chunk for each vertices chunk
205 		// size of the vertex count for each vertices chunk
206 		// size of the floats
207 		return (EMPTY_CHUNK_LENGTH + sizeof(CountType)) * blockCount + (ChunkLength)(3 * 3 * trianglesCount * sizeof(float));
208 	}
209 
210 	//------------------------------
calculateObjectLength(ChunkLength triangularMeshLength)211 	ChunkLength MeshBase::calculateObjectLength(ChunkLength triangularMeshLength)
212 	{
213 		// size of empty chunk
214 		// name of the object/mesh with null termination
215 		// triangle mesh size
216 		return EMPTY_CHUNK_LENGTH + (ChunkLength)(OBJECT_NAME_LENGTH) + triangularMeshLength;
217 	}
218 
219 	//------------------------------
calculateTotalObjectLengthMultiObject(ChunkLength triangularMeshesLength,ChunkLength blockCount)220 	ChunkLength MeshBase::calculateTotalObjectLengthMultiObject(ChunkLength triangularMeshesLength, ChunkLength blockCount)
221 	{
222 		// size of empty chunk for each block
223 		// name of the object/mesh with null termination for each block
224 		// triangle meshes sizes
225 		return blockCount*(EMPTY_CHUNK_LENGTH + (ChunkLength)(OBJECT_NAME_LENGTH)) + triangularMeshesLength;
226 	}
227 
228 	//------------------------------
calculateTrianglesCount()229 	size_t MeshBase::calculateTrianglesCount()
230 	{
231 		return mMeshData.trianglesCount;
232 	}
233 
234 	//------------------------------
235 // 	ChunkLength MeshBase::calculateMaterialNamesLength( const COLLADAFW::MaterialBindingArray& materialBindings)
236 // 	{
237 // 		ChunkLength length = 0;
238 //
239 // 		for ( size_t i = 0, count = materialBindings.getCount(); i < count; ++i)
240 // 		{
241 // 			const COLLADAFW::InstanceGeometry::MaterialBinding& materialBinding = materialBindings[i];
242 // 			// length of the name plus one for null termination
243 // 			length += calculateMaterialNameLengthFromMaterialBinding(materialBinding);
244 // 		}
245 // 		return length;
246 // 	}
247 
248 	//------------------------------
calculateFacesMaterialsLength(CountType trianglesCount,const COLLADAFW::MaterialBindingArray & materialBindings)249 	ChunkLength MeshBase::calculateFacesMaterialsLength(CountType trianglesCount, const COLLADAFW::MaterialBindingArray& materialBindings)
250 	{
251 		// the size is determined by:
252 		// 1) the number of materials and their name length
253 		// 2) the triangles count
254 
255 		if ( trianglesCount == 0)
256 		{
257 			return 0;
258 		}
259 
260 		if ( materialBindings.empty() )
261 		{
262 			return 0;
263 			// TODO: This works only if either all faces have a material assigned or none
264 		}
265 
266 		ChunkLength length = 0;
267 		// each triangle appears exactly once in a facenum array
268 		length += trianglesCount * sizeof(IndexType);
269 
270 		ChunkLength materialsCount = (ChunkLength)materialBindings.getCount();
271 
272 		//fix size for each material
273 		// empty chunk length of faces material
274 		// material name length
275 		// nFaces length
276 		length += (EMPTY_CHUNK_LENGTH + sizeof(CountType) + Writer::getMaterialNameLength() ) * materialsCount;
277 
278 		return length;
279 	}
280 
281 	//------------------------------
calculateFacesDescriptionLength(CountType trianglesCount,ChunkLength facesMaterialsLength)282 	ChunkLength MeshBase::calculateFacesDescriptionLength(CountType trianglesCount, ChunkLength facesMaterialsLength)
283 	{
284 		// size of empty chunk
285 		// faces count
286 		// triangles indices + flag
287 		// faces materials
288 		return EMPTY_CHUNK_LENGTH + sizeof(CountType) + sizeof(CountType) * 4 * trianglesCount + facesMaterialsLength;
289 	}
290 
291 	//------------------------------
calculateFacesDescriptionLengthMultiObject(size_t trianglesCount,ChunkLength blockCount,ChunkLength facesMaterialsLength,ChunkLength remainderFacesMaterialsLength,ChunkLength fullBlocksCount)292 	ChunkLength MeshBase::calculateFacesDescriptionLengthMultiObject(size_t trianglesCount, ChunkLength blockCount, ChunkLength facesMaterialsLength, ChunkLength remainderFacesMaterialsLength, ChunkLength fullBlocksCount)
293 	{
294 		// size of empty chunk for each block
295 		// faces count for each block
296 		// triangles indices + flag
297 		// faces materials for each block
298 		return   (EMPTY_CHUNK_LENGTH + sizeof(CountType))*blockCount
299 			+ facesMaterialsLength * fullBlocksCount + remainderFacesMaterialsLength
300 			+ sizeof(CountType) * 4 * trianglesCount;
301 	}
302 
303 
304 // 	ChunkLength MeshBase::calculateMaterialNameLengthFromMaterialBinding( const COLLADAFW::InstanceGeometry::MaterialBinding& materialBinding)
305 // 	{
306 // 		COLLADAFW::MaterialId materialId = materialBinding.getMaterialId();
307 // 		static char mBuffer[Common::Itoa<COLLADAFW::MaterialId>::MINIMUM_BUFFERSIZE_10];
308 // 		size_t bytesWritten = Common::itoa( materialId, mBuffer, 10);
309 // 		return (ChunkLength)(sizeof(MATERIAL_NAME_PREFIX) + bytesWritten);
310 // 	}
311 
312 	// Do not use in threads!!!!!!!!!!!
313 // 	const char* MeshBase::calculateMaterialNameFromMaterialBinding( const COLLADAFW::InstanceGeometry::MaterialBinding& materialBinding, ChunkLength& length)
314 // 	{
315 // 		COLLADAFW::MaterialId materialId = materialBinding.getMaterialId();
316 // 		static char buffer[Common::Itoa<COLLADAFW::MaterialId>::MINIMUM_BUFFERSIZE_10 + sizeof(MATERIAL_NAME_PREFIX)];
317 // 		static bool bufferInitialized = false;
318 // 		if ( !bufferInitialized )
319 // 		{
320 // 			memcpy(buffer, MATERIAL_NAME_PREFIX, sizeof(MATERIAL_NAME_PREFIX));
321 // 			bufferInitialized = true;
322 // 		}
323 // 		size_t bytesWritten = Common::itoa( materialId, buffer + sizeof(MATERIAL_NAME_PREFIX) - 1, 10);
324 // 		length =  (ChunkLength)(sizeof(MATERIAL_NAME_PREFIX) + bytesWritten );
325 // 		return buffer;
326 // 	}
327 
328 } // namespace DAE23ds
329