vrshoot

view libs/assimp/FBXMeshGeometry.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file FBXMeshGeometry.cpp
42 * @brief Assimp::FBX::MeshGeometry implementation
43 */
44 #include "AssimpPCH.h"
46 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
48 #include <functional>
50 #include "FBXParser.h"
51 #include "FBXDocument.h"
52 #include "FBXImporter.h"
53 #include "FBXImportSettings.h"
54 #include "FBXDocumentUtil.h"
57 namespace Assimp {
58 namespace FBX {
60 using namespace Util;
63 // ------------------------------------------------------------------------------------------------
64 Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
65 : Object(id, element,name)
66 , skin()
67 {
68 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
69 BOOST_FOREACH(const Connection* con, conns) {
70 const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
71 if(sk) {
72 skin = sk;
73 break;
74 }
75 }
76 }
79 // ------------------------------------------------------------------------------------------------
80 Geometry::~Geometry()
81 {
83 }
87 // ------------------------------------------------------------------------------------------------
88 MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
89 : Geometry(id, element,name, doc)
90 {
91 const Scope* sc = element.Compound();
92 if (!sc) {
93 DOMError("failed to read Geometry object (class: Mesh), no data scope found");
94 }
96 // must have Mesh elements:
97 const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
98 const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
100 // optional Mesh elements:
101 const ElementCollection& Layer = sc->GetCollection("Layer");
103 std::vector<aiVector3D> tempVerts;
104 ParseVectorDataArray(tempVerts,Vertices);
106 if(tempVerts.empty()) {
107 FBXImporter::LogWarn("encountered mesh with no vertices");
108 return;
109 }
111 std::vector<int> tempFaces;
112 ParseVectorDataArray(tempFaces,PolygonVertexIndex);
114 if(tempFaces.empty()) {
115 FBXImporter::LogWarn("encountered mesh with no faces");
116 return;
117 }
119 vertices.reserve(tempFaces.size());
120 faces.reserve(tempFaces.size() / 3);
122 mapping_offsets.resize(tempVerts.size());
123 mapping_counts.resize(tempVerts.size(),0);
124 mappings.resize(tempFaces.size());
126 const size_t vertex_count = tempVerts.size();
128 // generate output vertices, computing an adjacency table to
129 // preserve the mapping from fbx indices to *this* indexing.
130 unsigned int count = 0;
131 BOOST_FOREACH(int index, tempFaces) {
132 const int absi = index < 0 ? (-index - 1) : index;
133 if(static_cast<size_t>(absi) >= vertex_count) {
134 DOMError("polygon vertex index out of range",&PolygonVertexIndex);
135 }
137 vertices.push_back(tempVerts[absi]);
138 ++count;
140 ++mapping_counts[absi];
142 if (index < 0) {
143 faces.push_back(count);
144 count = 0;
145 }
146 }
148 unsigned int cursor = 0;
149 for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
150 mapping_offsets[i] = cursor;
151 cursor += mapping_counts[i];
153 mapping_counts[i] = 0;
154 }
156 cursor = 0;
157 BOOST_FOREACH(int index, tempFaces) {
158 const int absi = index < 0 ? (-index - 1) : index;
159 mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor++;
160 }
162 // if settings.readAllLayers is true:
163 // * read all layers, try to load as many vertex channels as possible
164 // if settings.readAllLayers is false:
165 // * read only the layer with index 0, but warn about any further layers
166 for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
167 const TokenList& tokens = (*it).second->Tokens();
169 const char* err;
170 const int index = ParseTokenAsInt(*tokens[0], err);
171 if(err) {
172 DOMError(err,&element);
173 }
175 if(doc.Settings().readAllLayers || index == 0) {
176 const Scope& layer = GetRequiredScope(*(*it).second);
177 ReadLayer(layer);
178 }
179 else {
180 FBXImporter::LogWarn("ignoring additional geometry layers");
181 }
182 }
183 }
186 // ------------------------------------------------------------------------------------------------
187 MeshGeometry::~MeshGeometry()
188 {
190 }
194 // ------------------------------------------------------------------------------------------------
195 void MeshGeometry::ReadLayer(const Scope& layer)
196 {
197 const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
198 for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
199 const Scope& elayer = GetRequiredScope(*(*eit).second);
201 ReadLayerElement(elayer);
202 }
203 }
206 // ------------------------------------------------------------------------------------------------
207 void MeshGeometry::ReadLayerElement(const Scope& layerElement)
208 {
209 const Element& Type = GetRequiredElement(layerElement,"Type");
210 const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
212 const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
213 const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
215 const Scope& top = GetRequiredScope(element);
216 const ElementCollection candidates = top.GetCollection(type);
218 for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
219 const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
220 if(index == typedIndex) {
221 ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
222 return;
223 }
224 }
226 FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
227 << type << ", index: " << typedIndex);
228 }
231 // ------------------------------------------------------------------------------------------------
232 void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
233 {
234 const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
235 GetRequiredElement(source,"MappingInformationType"),0)
236 );
238 const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
239 GetRequiredElement(source,"ReferenceInformationType"),0)
240 );
242 if (type == "LayerElementUV") {
243 if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
244 FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
245 << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
246 return;
247 }
249 const Element* Name = source["Name"];
250 uvNames[index] = "";
251 if(Name) {
252 uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
253 }
255 ReadVertexDataUV(uvs[index],source,
256 MappingInformationType,
257 ReferenceInformationType
258 );
259 }
260 else if (type == "LayerElementMaterial") {
261 if (materials.size() > 0) {
262 FBXImporter::LogError("ignoring additional material layer");
263 return;
264 }
266 std::vector<int> temp_materials;
268 ReadVertexDataMaterials(temp_materials,source,
269 MappingInformationType,
270 ReferenceInformationType
271 );
273 // sometimes, there will be only negative entries. Drop the material
274 // layer in such a case (I guess it means a default material should
275 // be used). This is what the converter would do anyway, and it
276 // avoids loosing the material if there are more material layers
277 // coming of which at least one contains actual data (did observe
278 // that with one test file).
279 const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
280 if(count_neg == temp_materials.size()) {
281 FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
282 return;
283 }
285 std::swap(temp_materials, materials);
286 }
287 else if (type == "LayerElementNormal") {
288 if (normals.size() > 0) {
289 FBXImporter::LogError("ignoring additional normal layer");
290 return;
291 }
293 ReadVertexDataNormals(normals,source,
294 MappingInformationType,
295 ReferenceInformationType
296 );
297 }
298 else if (type == "LayerElementTangent") {
299 if (tangents.size() > 0) {
300 FBXImporter::LogError("ignoring additional tangent layer");
301 return;
302 }
304 ReadVertexDataTangents(tangents,source,
305 MappingInformationType,
306 ReferenceInformationType
307 );
308 }
309 else if (type == "LayerElementBinormal") {
310 if (binormals.size() > 0) {
311 FBXImporter::LogError("ignoring additional binormal layer");
312 return;
313 }
315 ReadVertexDataBinormals(binormals,source,
316 MappingInformationType,
317 ReferenceInformationType
318 );
319 }
320 else if (type == "LayerElementColor") {
321 if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
322 FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
323 << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
324 return;
325 }
327 ReadVertexDataColors(colors[index],source,
328 MappingInformationType,
329 ReferenceInformationType
330 );
331 }
332 }
335 // ------------------------------------------------------------------------------------------------
336 // Lengthy utility function to read and resolve a FBX vertex data array - that is, the
337 // output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
338 // tangents ..
339 template <typename T>
340 void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
341 const std::string& MappingInformationType,
342 const std::string& ReferenceInformationType,
343 const char* dataElementName,
344 const char* indexDataElementName,
345 size_t vertex_count,
346 const std::vector<unsigned int>& mapping_counts,
347 const std::vector<unsigned int>& mapping_offsets,
348 const std::vector<unsigned int>& mappings)
349 {
350 std::vector<T> tempUV;
351 ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
353 // handle permutations of Mapping and Reference type - it would be nice to
354 // deal with this more elegantly and with less redundancy, but right
355 // now it seems unavoidable.
356 if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
357 data_out.resize(vertex_count);
358 for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
360 const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
361 for (unsigned int j = istart; j < iend; ++j) {
362 data_out[mappings[j]] = tempUV[i];
363 }
364 }
365 }
366 else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
367 data_out.resize(vertex_count);
369 std::vector<int> uvIndices;
370 ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
372 for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
374 const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
375 for (unsigned int j = istart; j < iend; ++j) {
376 if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
377 DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
378 }
379 data_out[mappings[j]] = tempUV[uvIndices[i]];
380 }
381 }
382 }
383 else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
384 if (tempUV.size() != vertex_count) {
385 FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
386 << tempUV.size() << ", expected " << vertex_count
387 );
388 return;
389 }
391 data_out.swap(tempUV);
392 }
393 else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
394 data_out.resize(vertex_count);
396 std::vector<int> uvIndices;
397 ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
399 if (uvIndices.size() != vertex_count) {
400 FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
401 return;
402 }
404 unsigned int next = 0;
405 BOOST_FOREACH(int i, uvIndices) {
406 if(static_cast<size_t>(i) >= tempUV.size()) {
407 DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
408 }
410 data_out[next++] = tempUV[i];
411 }
412 }
413 else {
414 FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
415 << MappingInformationType << "," << ReferenceInformationType);
416 }
417 }
419 // ------------------------------------------------------------------------------------------------
420 void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
421 const std::string& MappingInformationType,
422 const std::string& ReferenceInformationType)
423 {
424 ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
425 "Normals",
426 "NormalsIndex",
427 vertices.size(),
428 mapping_counts,
429 mapping_offsets,
430 mappings);
431 }
434 // ------------------------------------------------------------------------------------------------
435 void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
436 const std::string& MappingInformationType,
437 const std::string& ReferenceInformationType)
438 {
439 ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
440 "UV",
441 "UVIndex",
442 vertices.size(),
443 mapping_counts,
444 mapping_offsets,
445 mappings);
446 }
449 // ------------------------------------------------------------------------------------------------
450 void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
451 const std::string& MappingInformationType,
452 const std::string& ReferenceInformationType)
453 {
454 ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
455 "Colors",
456 "ColorIndex",
457 vertices.size(),
458 mapping_counts,
459 mapping_offsets,
460 mappings);
461 }
464 // ------------------------------------------------------------------------------------------------
465 void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
466 const std::string& MappingInformationType,
467 const std::string& ReferenceInformationType)
468 {
469 ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
470 "Tangent",
471 "TangentIndex",
472 vertices.size(),
473 mapping_counts,
474 mapping_offsets,
475 mappings);
476 }
479 // ------------------------------------------------------------------------------------------------
480 void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
481 const std::string& MappingInformationType,
482 const std::string& ReferenceInformationType)
483 {
484 ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
485 "Binormal",
486 "BinormalIndex",
487 vertices.size(),
488 mapping_counts,
489 mapping_offsets,
490 mappings);
491 }
494 // ------------------------------------------------------------------------------------------------
495 void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
496 const std::string& MappingInformationType,
497 const std::string& ReferenceInformationType)
498 {
499 const size_t face_count = faces.size();
500 ai_assert(face_count);
502 // materials are handled separately. First of all, they are assigned per-face
503 // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
504 // has a slightly different meaning for materials.
505 ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
507 if (MappingInformationType == "AllSame") {
508 // easy - same material for all faces
509 if (materials_out.empty()) {
510 FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
511 return;
512 }
513 else if (materials_out.size() > 1) {
514 FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
515 materials_out.clear();
516 }
518 materials.assign(vertices.size(),materials_out[0]);
519 }
520 else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
521 materials.resize(face_count);
523 if(materials_out.size() != face_count) {
524 FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
525 << materials_out.size() << ", expected " << face_count
526 );
527 return;
528 }
529 }
530 else {
531 FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
532 << MappingInformationType << "," << ReferenceInformationType);
533 }
534 }
536 } // !FBX
537 } // !Assimp
539 #endif