From 00277d93f2a56ace39fc3088b4c62308001ae192 Mon Sep 17 00:00:00 2001 From: Tommy Date: Wed, 28 Mar 2018 15:47:27 +0200 Subject: [PATCH 01/30] Tidier FBXExportNode construction with properties. --- code/FBXExportNode.h | 9 +-- code/FBXExporter.cpp | 136 +++++++++++++++++++------------------------ 2 files changed, 64 insertions(+), 81 deletions(-) diff --git a/code/FBXExportNode.h b/code/FBXExportNode.h index edce8f700..2539a9458 100644 --- a/code/FBXExportNode.h +++ b/code/FBXExportNode.h @@ -69,11 +69,12 @@ public: // public data members public: // constructors Node() = default; Node(const std::string& n) : name(n) {} - Node(const std::string& n, const FBX::Property &p) + + // convenience template to construct with properties directly + template + Node(const std::string& n, const More... more) : name(n) - { properties.push_back(p); } - Node(const std::string& n, const std::vector &pv) - : name(n), properties(pv) {} + { AddProperties(more...); } public: // functions to add properties or children // add a single property to the node diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index 7dcf752da..8b633462d 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -520,7 +520,7 @@ void FBXExporter::WriteDefinitions () // GlobalSettings // this seems to always be here in Maya exports - n = FBX::Node("ObjectType", Property("GlobalSettings")); + n = FBX::Node("ObjectType", "GlobalSettings"); count = 1; n.AddChild("Count", count); object_nodes.push_back(n); @@ -531,9 +531,9 @@ void FBXExporter::WriteDefinitions () // but no harm seems to come of leaving it out. count = mScene->mNumAnimations; if (count) { - n = FBX::Node("ObjectType", Property("AnimationStack")); + n = FBX::Node("ObjectType", "AnimationStack"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxAnimStack")); + pt = FBX::Node("PropertyTemplate", "FbxAnimStack"); p = FBX::Node("Properties70"); p.AddP70string("Description", ""); p.AddP70time("LocalStart", 0); @@ -553,9 +553,9 @@ void FBXExporter::WriteDefinitions () // so there will be one per aiAnimation count = mScene->mNumAnimations; if (count) { - n = FBX::Node("ObjectType", Property("AnimationLayer")); + n = FBX::Node("ObjectType", "AnimationLayer"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FBXAnimLayer")); + pt = FBX::Node("PropertyTemplate", "FBXAnimLayer"); p = FBX::Node("Properties70"); p.AddP70("Weight", "Number", "", "A", double(100)); p.AddP70bool("Mute", 0); @@ -583,9 +583,9 @@ void FBXExporter::WriteDefinitions () count = 1; // TODO: select properly if (count) { // FbxSkeleton - n = FBX::Node("ObjectType", Property("NodeAttribute")); + n = FBX::Node("ObjectType", "NodeAttribute"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxSkeleton")); + pt = FBX::Node("PropertyTemplate", "FbxSkeleton"); p = FBX::Node("Properties70"); p.AddP70color("Color", 0.8, 0.8, 0.8); p.AddP70double("Size", 33.333333333333); @@ -601,9 +601,9 @@ void FBXExporter::WriteDefinitions () // <~~ node heirarchy count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node) if (count) { - n = FBX::Node("ObjectType", Property("Model")); + n = FBX::Node("ObjectType", "Model"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxNode")); + pt = FBX::Node("PropertyTemplate", "FbxNode"); p = FBX::Node("Properties70"); p.AddP70enum("QuaternionInterpolate", 0); p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0); @@ -698,9 +698,9 @@ void FBXExporter::WriteDefinitions () // <~~ aiMesh count = mScene->mNumMeshes; if (count) { - n = FBX::Node("ObjectType", Property("Geometry")); + n = FBX::Node("ObjectType", "Geometry"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxMesh")); + pt = FBX::Node("PropertyTemplate", "FbxMesh"); p = FBX::Node("Properties70"); p.AddP70color("Color", 0, 0, 0); p.AddP70vector("BBoxMin", 0, 0, 0); @@ -724,7 +724,7 @@ void FBXExporter::WriteDefinitions () count = mScene->mNumMaterials; if (count) { bool has_phong = has_phong_mat(mScene); - n = FBX::Node("ObjectType", Property("Material")); + n = FBX::Node("ObjectType", "Material"); n.AddChild("Count", count); pt = FBX::Node("PropertyTemplate"); if (has_phong) { @@ -771,9 +771,9 @@ void FBXExporter::WriteDefinitions () // one for each image file. count = int32_t(count_images(mScene)); if (count) { - n = FBX::Node("ObjectType", Property("Video")); + n = FBX::Node("ObjectType", "Video"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxVideo")); + pt = FBX::Node("PropertyTemplate", "FbxVideo"); p = FBX::Node("Properties70"); p.AddP70bool("ImageSequence", 0); p.AddP70int("ImageSequenceOffset", 0); @@ -800,9 +800,9 @@ void FBXExporter::WriteDefinitions () // <~~ aiTexture count = int32_t(count_textures(mScene)); if (count) { - n = FBX::Node("ObjectType", Property("Texture")); + n = FBX::Node("ObjectType", "Texture"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxFileTexture")); + pt = FBX::Node("PropertyTemplate", "FbxFileTexture"); p = FBX::Node("Properties70"); p.AddP70enum("TextureTypeUse", 0); p.AddP70numberA("Texture alpha", 1.0); @@ -829,9 +829,9 @@ void FBXExporter::WriteDefinitions () // AnimationCurveNode / FbxAnimCurveNode count = mScene->mNumAnimations * 3; if (count) { - n = FBX::Node("ObjectType", Property("AnimationCurveNode")); + n = FBX::Node("ObjectType", "AnimationCurveNode"); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("FbxAnimCurveNode")); + pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode"); p = FBX::Node("Properties70"); p.AddP70("d", "Compound", "", ""); pt.AddChild(p); @@ -843,7 +843,7 @@ void FBXExporter::WriteDefinitions () // AnimationCurve / FbxAnimCurve count = mScene->mNumAnimations * 9; if (count) { - n = FBX::Node("ObjectType", Property("AnimationCurve")); + n = FBX::Node("ObjectType", "AnimationCurve"); n.AddChild("Count", count); object_nodes.push_back(n); total_count += count; @@ -856,7 +856,7 @@ void FBXExporter::WriteDefinitions () if (mesh->HasBones()) { ++count; } } if (count) { - n = FBX::Node("ObjectType", Property("Pose")); + n = FBX::Node("ObjectType", "Pose"); n.AddChild("Count", count); object_nodes.push_back(n); total_count += count; @@ -865,7 +865,7 @@ void FBXExporter::WriteDefinitions () // Deformer count = int32_t(count_deformers(mScene)); if (count) { - n = FBX::Node("ObjectType", Property("Deformer")); + n = FBX::Node("ObjectType", "Deformer"); n.AddChild("Count", count); object_nodes.push_back(n); total_count += count; @@ -874,9 +874,9 @@ void FBXExporter::WriteDefinitions () // (template) count = 0; if (count) { - n = FBX::Node("ObjectType", Property("")); + n = FBX::Node("ObjectType", ""); n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", Property("")); + pt = FBX::Node("PropertyTemplate", ""); p = FBX::Node("Properties70"); pt.AddChild(p); n.AddChild(pt); @@ -1008,7 +1008,7 @@ void FBXExporter::WriteObjects () // normals, if any if (m->HasNormals()) { - FBX::Node normals("LayerElementNormal", Property(int32_t(0))); + FBX::Node normals("LayerElementNormal", int32_t(0)); normals.Begin(outstream); normals.DumpProperties(outstream); normals.EndProperties(outstream); @@ -1055,7 +1055,7 @@ void FBXExporter::WriteObjects () err << " but may be incorrectly interpreted on load."; DefaultLogger::get()->warn(err.str()); } - FBX::Node uv("LayerElementUV", Property(int32_t(uvi))); + FBX::Node uv("LayerElementUV", int32_t(uvi)); uv.Begin(outstream); uv.DumpProperties(outstream); uv.EndProperties(outstream); @@ -1100,7 +1100,7 @@ void FBXExporter::WriteObjects () // i'm not really sure why this material section exists, // as the material is linked via "Connections". // it seems to always have the same "0" value. - FBX::Node mat("LayerElementMaterial", Property(int32_t(0))); + FBX::Node mat("LayerElementMaterial", int32_t(0)); mat.AddChild("Version", int32_t(101)); mat.AddChild("Name", ""); mat.AddChild("MappingInformationType", "AllSame"); @@ -1112,7 +1112,7 @@ void FBXExporter::WriteObjects () // finally we have the layer specifications, // which select the normals / UV set / etc to use. // TODO: handle multiple uv sets correctly? - FBX::Node layer("Layer", Property(int32_t(0))); + FBX::Node layer("Layer", int32_t(0)); layer.AddChild("Version", int32_t(100)); FBX::Node le("LayerElement"); le.AddChild("Type", "LayerElementNormal"); @@ -1408,14 +1408,12 @@ void FBXExporter::WriteObjects () const int64_t texture_uid = generate_uid(); // link the texture to the material - FBX::Node c("C"); - c.AddProperties("OP", texture_uid, material_uid, prop_name); - connections.push_back(c); + connections.emplace_back( + "C", "OP", texture_uid, material_uid, prop_name + ); // link the image data to the texture - c = FBX::Node("C"); - c.AddProperties("OO", image_uid, texture_uid); - connections.push_back(c); + connections.emplace_back("C", "OO", image_uid, texture_uid); // now write the actual texture node FBX::Node tnode("Texture"); @@ -1598,9 +1596,7 @@ void FBXExporter::WriteObjects () dnode.Dump(outstream); // connect it - FBX::Node c("C"); - c.AddProperties("OO", deformer_uid, mesh_uids[mi]); - connections.push_back(c); // TODO: emplace_back + connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); // we will be indexing by vertex... // but there might be a different number of "vertices" @@ -1744,14 +1740,14 @@ void FBXExporter::WriteObjects () sdnode.Dump(outstream); // lastly, connect to the parent deformer - c = FBX::Node("C"); - c.AddProperties("OO", subdeformer_uid, deformer_uid); - connections.push_back(c); // TODO: emplace_back + connections.emplace_back( + "C", "OO", subdeformer_uid, deformer_uid + ); // we also need to connect the limb node to the subdeformer. - c = FBX::Node("C"); - c.AddProperties("OO", node_uids[bone_node], subdeformer_uid); - connections.push_back(c); // TODO: emplace_back + connections.emplace_back( + "C", "OO", node_uids[bone_node], subdeformer_uid + ); } // if we cannot create a valid FBX file, simply die. @@ -1943,9 +1939,9 @@ void FBXExporter::WriteObjects () alnode.End(outstream, true); // connect to the relevant animstack - FBX::Node c("C"); - c.AddProperties("OO", animlayer_uid, animation_stack_uids[ai]); - connections.push_back(c); // TODO: emplace_back + connections.emplace_back( + "C", "OO", animlayer_uid, animation_stack_uids[ai] + ); } // AnimCurveNode - three per aiNodeAnim @@ -2240,9 +2236,7 @@ void FBXExporter::WriteModelNodes( node_uid = generate_uid(); node_uids[node] = node_uid; } - FBX::Node c("C"); - c.AddProperties("OO", node_uid, parent_uid); - connections.push_back(c); + connections.emplace_back("C", "OO", node_uid, parent_uid); } // what type of node is this? @@ -2250,17 +2244,15 @@ void FBXExporter::WriteModelNodes( // handled later } else if (node->mNumMeshes == 1) { // connect to child mesh, which should have been written previously - FBX::Node c("C"); - c.AddProperties("OO", mesh_uids[node->mMeshes[0]], node_uid); - connections.push_back(c); + connections.emplace_back( + "C", "OO", mesh_uids[node->mMeshes[0]], node_uid + ); // also connect to the material for the child mesh - c = FBX::Node("C"); - c.AddProperties( - "OO", + connections.emplace_back( + "C", "OO", material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex], node_uid ); - connections.push_back(c); // write model node WriteModelNode(outstream, node, node_uid, "Mesh", transform_chain); } else if (limbnodes.count(node)) { @@ -2274,9 +2266,7 @@ void FBXExporter::WriteModelNodes( na.AddChild("TypeFlags", Property("Skeleton")); na.Dump(outstream); // and connect them - FBX::Node c("C"); - c.AddProperties("OO", node_attribute_uid, node_uid); - connections.push_back(c); + connections.emplace_back("C", "OO", node_attribute_uid, node_uid); } else { // generate a null node so we can add children to it WriteModelNode(outstream, node, node_uid, "Null", transform_chain); @@ -2288,23 +2278,19 @@ void FBXExporter::WriteModelNodes( // make a new model node int64_t new_node_uid = generate_uid(); // connect to parent node - FBX::Node c("C"); - c.AddProperties("OO", new_node_uid, node_uid); - connections.push_back(c); + connections.emplace_back("C", "OO", new_node_uid, node_uid); // connect to child mesh, which should have been written previously - c = FBX::Node("C"); - c.AddProperties("OO", mesh_uids[node->mMeshes[i]], new_node_uid); - connections.push_back(c); + connections.emplace_back( + "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid + ); // also connect to the material for the child mesh - c = FBX::Node("C"); - c.AddProperties( - "OO", + connections.emplace_back( + "C", "OO", material_uids[ mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex ], new_node_uid ); - connections.push_back(c); // write model node FBX::Node m("Model"); // take name from mesh name, if it exists @@ -2346,13 +2332,9 @@ void FBXExporter::WriteAnimationCurveNode( n.AddChild(p); n.Dump(outstream); // connect to layer - FBX::Node cl("C"); - cl.AddProperties("OO", uid, layer_uid); - this->connections.push_back(cl); // TODO: emplace_back + this->connections.emplace_back("C", "OO", uid, layer_uid); // connect to bone - FBX::Node cb("C"); - cb.AddProperties("OP", uid, node_uid, property_name); - this->connections.push_back(cb); // TODO: emplace_back + this->connections.emplace_back("C", "OP", uid, node_uid, property_name); } @@ -2380,9 +2362,9 @@ void FBXExporter::WriteAnimationCurve( std::vector{static_cast(times.size())} ); n.Dump(outstream); - FBX::Node c("C"); - c.AddProperties("OP", curve_uid, curvenode_uid, property_link); - this->connections.push_back(c); // TODO: emplace_back + this->connections.emplace_back( + "C", "OP", curve_uid, curvenode_uid, property_link + ); } From aadb413fc07dccb8fe5b8fee8704b941f5713816 Mon Sep 17 00:00:00 2001 From: Tommy Date: Wed, 28 Mar 2018 16:09:07 +0200 Subject: [PATCH 02/30] Explicit handling of an FBXExportNode edge-case. --- code/FBXExportNode.cpp | 2 +- code/FBXExportNode.h | 3 +++ code/FBXExporter.cpp | 15 +++++---------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/code/FBXExportNode.cpp b/code/FBXExportNode.cpp index 596901989..621e72f09 100644 --- a/code/FBXExportNode.cpp +++ b/code/FBXExportNode.cpp @@ -168,7 +168,7 @@ void FBX::Node::Dump(Assimp::StreamWriterLE &s) DumpChildren(s); // finish, filling in end offset placeholder - End(s, !children.empty()); + End(s, force_has_children || !children.empty()); } void FBX::Node::Begin(Assimp::StreamWriterLE &s) diff --git a/code/FBXExportNode.h b/code/FBXExportNode.h index 2539a9458..58d3d14ee 100644 --- a/code/FBXExportNode.h +++ b/code/FBXExportNode.h @@ -66,6 +66,9 @@ public: // public data members std::vector properties; // node properties std::vector children; // child nodes + // some nodes always pretend they have children... + bool force_has_children = false; + public: // constructors Node() = default; Node(const std::string& n) : name(n) {} diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index 8b633462d..46782cc2e 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -419,6 +419,7 @@ void FBXExporter::WriteReferences () // always empty for now. // not really sure what this is for. FBX::Node n("References"); + n.force_has_children = true; n.Dump(outfile); } @@ -1914,11 +1915,8 @@ void FBXExporter::WriteObjects () // this node absurdly always pretends it has children // (in this case it does, but just in case...) - asnode.Begin(outstream); - asnode.DumpProperties(outstream); - asnode.EndProperties(outstream); - asnode.DumpChildren(outstream); - asnode.End(outstream, true); + asnode.force_has_children = true; + asnode.Dump(outstream); // note: animation stacks are not connected to anything } @@ -1932,11 +1930,8 @@ void FBXExporter::WriteObjects () alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", ""); // this node absurdly always pretends it has children - alnode.Begin(outstream); - alnode.DumpProperties(outstream); - alnode.EndProperties(outstream); - alnode.DumpChildren(outstream); - alnode.End(outstream, true); + alnode.force_has_children = true; + alnode.Dump(outstream); // connect to the relevant animstack connections.emplace_back( From e549705af0aa53a611a7739aa5567b392e4bea63 Mon Sep 17 00:00:00 2001 From: Tommy Date: Wed, 28 Mar 2018 21:38:22 +0200 Subject: [PATCH 03/30] StreamWriter: add a PutChar method to write a single char. --- include/assimp/StreamWriter.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index 6f492df90..5ce3b172b 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -203,6 +203,12 @@ public: Put(n); } + // --------------------------------------------------------------------- + /** Write a single character to the stream */ + void PutChar(char c) { + Put(c); + } + // --------------------------------------------------------------------- /** Write an aiString to the stream */ void PutString(const aiString& s) From 826243f289cb4cdbc1c5e79dc8593ce6805a5f49 Mon Sep 17 00:00:00 2001 From: Tommy Date: Wed, 28 Mar 2018 21:40:26 +0200 Subject: [PATCH 04/30] Implement ascii FBX export. It's available under the 'fbxa' format id. --- code/Exporter.cpp | 4 +- code/FBXExportNode.cpp | 376 ++++++++++++++++++++++++++++++++----- code/FBXExportNode.h | 81 ++++++-- code/FBXExportProperty.cpp | 155 +++++++++++++-- code/FBXExportProperty.h | 6 +- code/FBXExporter.cpp | 275 ++++++++++++++++++--------- code/FBXExporter.h | 14 ++ 7 files changed, 747 insertions(+), 164 deletions(-) diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 49523e658..b7478c0be 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -98,7 +98,7 @@ void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportPrope void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); -//void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); // ------------------------------------------------------------------------------------------------ @@ -173,7 +173,7 @@ Exporter::ExportFormatEntry gExporters[] = #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), - //Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), + Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER diff --git a/code/FBXExportNode.cpp b/code/FBXExportNode.cpp index 621e72f09..514d5f360 100644 --- a/code/FBXExportNode.cpp +++ b/code/FBXExportNode.cpp @@ -45,10 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXCommon.h" #include // StreamWriterLE +#include // DeadlyExportError #include #include +#include +#include // ostringstream #include // shared_ptr +#include // snprintf // AddP70 helpers... there's no usable pattern here, // so all are defined as separate functions. @@ -145,33 +149,174 @@ void FBX::Node::AddP70time( } +// public member functions for writing nodes to stream + +void FBX::Node::Dump( + std::shared_ptr outfile, + bool binary, int indent +) { + if (binary) { + Assimp::StreamWriterLE outstream(outfile); + DumpBinary(outstream); + } else { + std::ostringstream ss; + DumpAscii(ss, indent); + std::string s = ss.str(); + outfile->Write(s.c_str(), s.size(), 1); + } +} + +void FBX::Node::Dump( + Assimp::StreamWriterLE &outstream, + bool binary, int indent +) { + if (binary) { + DumpBinary(outstream); + } else { + std::ostringstream ss; + DumpAscii(ss, indent); + outstream.PutString(ss.str()); + } +} + + +// public member functions for low-level writing + +void FBX::Node::Begin( + Assimp::StreamWriterLE &s, + bool binary, int indent +) { + if (binary) { + BeginBinary(s); + } else { + // assume we're at the correct place to start already + (void)indent; + std::ostringstream ss; + BeginAscii(ss, indent); + s.PutString(ss.str()); + } +} + +void FBX::Node::DumpProperties( + Assimp::StreamWriterLE& s, + bool binary, int indent +) { + if (binary) { + DumpPropertiesBinary(s); + } else { + std::ostringstream ss; + DumpPropertiesAscii(ss, indent); + s.PutString(ss.str()); + } +} + +void FBX::Node::EndProperties( + Assimp::StreamWriterLE &s, + bool binary, int indent +) { + EndProperties(s, binary, indent, properties.size()); +} + +void FBX::Node::EndProperties( + Assimp::StreamWriterLE &s, + bool binary, int indent, + size_t num_properties +) { + if (binary) { + EndPropertiesBinary(s, num_properties); + } else { + // nothing to do + (void)indent; + } +} + +void FBX::Node::BeginChildren( + Assimp::StreamWriterLE &s, + bool binary, int indent +) { + if (binary) { + // nothing to do + } else { + std::ostringstream ss; + BeginChildrenAscii(ss, indent); + s.PutString(ss.str()); + } +} + +void FBX::Node::DumpChildren( + Assimp::StreamWriterLE& s, + bool binary, int indent +) { + if (binary) { + DumpChildrenBinary(s); + } else { + std::ostringstream ss; + DumpChildrenAscii(ss, indent); + s.PutString(ss.str()); + } +} + +void FBX::Node::End( + Assimp::StreamWriterLE &s, + bool binary, int indent, + bool has_children +) { + if (binary) { + EndBinary(s, has_children); + } else { + std::ostringstream ss; + EndAscii(ss, indent, has_children); + s.PutString(ss.str()); + } +} + + // public member functions for writing to binary fbx -void FBX::Node::Dump(std::shared_ptr outfile) -{ - Assimp::StreamWriterLE outstream(outfile); - Dump(outstream); -} - -void FBX::Node::Dump(Assimp::StreamWriterLE &s) +void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s) { // write header section (with placeholders for some things) - Begin(s); + BeginBinary(s); // write properties - DumpProperties(s); + DumpPropertiesBinary(s); // go back and fill in property related placeholders - EndProperties(s, properties.size()); + EndPropertiesBinary(s, properties.size()); // write children - DumpChildren(s); + DumpChildrenBinary(s); // finish, filling in end offset placeholder - End(s, force_has_children || !children.empty()); + EndBinary(s, force_has_children || !children.empty()); } -void FBX::Node::Begin(Assimp::StreamWriterLE &s) + +// public member functions for writing to ascii fbx + +void FBX::Node::DumpAscii(std::ostream &s, int indent) +{ + // write name + BeginAscii(s, indent); + + // write properties + DumpPropertiesAscii(s, indent); + + if (force_has_children || !children.empty()) { + // begin children (with a '{') + BeginChildrenAscii(s, indent + 1); + // write children + DumpChildrenAscii(s, indent + 1); + } + + // finish (also closing the children bracket '}') + EndAscii(s, indent, force_has_children || !children.empty()); +} + + +// private member functions for low-level writing to fbx + +void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s) { // remember start pos so we can come back and write the end pos this->start_pos = s.Tell(); @@ -189,26 +334,14 @@ void FBX::Node::Begin(Assimp::StreamWriterLE &s) this->property_start = s.Tell(); } -void FBX::Node::DumpProperties(Assimp::StreamWriterLE& s) +void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s) { for (auto &p : properties) { - p.Dump(s); + p.DumpBinary(s); } } -void FBX::Node::DumpChildren(Assimp::StreamWriterLE& s) -{ - for (FBX::Node& child : children) { - child.Dump(s); - } -} - -void FBX::Node::EndProperties(Assimp::StreamWriterLE &s) -{ - EndProperties(s, properties.size()); -} - -void FBX::Node::EndProperties( +void FBX::Node::EndPropertiesBinary( Assimp::StreamWriterLE &s, size_t num_properties ) { @@ -222,7 +355,14 @@ void FBX::Node::EndProperties( s.Seek(pos); } -void FBX::Node::End( +void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s) +{ + for (FBX::Node& child : children) { + child.DumpBinary(s); + } +} + +void FBX::Node::EndBinary( Assimp::StreamWriterLE &s, bool has_children ) { @@ -237,48 +377,192 @@ void FBX::Node::End( } -// static member functions +void FBX::Node::BeginAscii(std::ostream& s, int indent) +{ + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << name << ": "; +} -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. +void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent) +{ + for (size_t i = 0; i < properties.size(); ++i) { + if (i > 0) { s << ", "; } + properties[i].DumpAscii(s, indent); + } +} + +void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent) +{ + // only call this if there are actually children + s << " {"; + (void)indent; +} + +void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent) +{ + // children will need a lot of padding and corralling + if (children.size() || force_has_children) { + for (size_t i = 0; i < children.size(); ++i) { + // no compression in ascii files, so skip this node if it exists + if (children[i].name == "EncryptionType") { continue; } + // the child can dump itself + children[i].DumpAscii(s, indent); + } + } +} + +void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) +{ + if (!has_children) { return; } // nothing to do + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << "}"; +} + +// private helpers for static member functions + +// ascii property node from vector of doubles +void FBX::Node::WritePropertyNodeAscii( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + int indent +){ + char buffer[32]; + FBX::Node node(name); + node.Begin(s, false, indent); + std::string vsize = std::to_string(v.size()); + // * { + s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); + // indent + 1 + for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } + // a: value,value,value,... + s.PutString("a: "); + int count = 0; + for (size_t i = 0; i < v.size(); ++i) { + if (i > 0) { s.PutChar(','); } + int len = snprintf(buffer, sizeof(buffer), "%f", v[i]); + count += len; + if (count > 2048) { s.PutChar('\n'); count = 0; } + if (len < 0 || len > 31) { + // this should never happen + throw DeadlyExportError("failed to convert double to string"); + } + for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } + } + // } + s.PutChar('\n'); + for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } + s.PutChar('}'); s.PutChar(' '); + node.End(s, false, indent, false); +} + +// ascii property node from vector of int32_t +void FBX::Node::WritePropertyNodeAscii( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + int indent +){ + char buffer[32]; + FBX::Node node(name); + node.Begin(s, false, indent); + std::string vsize = std::to_string(v.size()); + // * { + s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); + // indent + 1 + for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } + // a: value,value,value,... + s.PutString("a: "); + int count = 0; + for (size_t i = 0; i < v.size(); ++i) { + if (i > 0) { s.PutChar(','); } + int len = snprintf(buffer, sizeof(buffer), "%d", v[i]); + count += len; + if (count > 2048) { s.PutChar('\n'); count = 0; } + if (len < 0 || len > 31) { + // this should never happen + throw DeadlyExportError("failed to convert double to string"); + } + for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } + } + // } + s.PutChar('\n'); + for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } + s.PutChar('}'); s.PutChar(' '); + node.End(s, false, indent, false); +} + +// binary property node from vector of doubles // TODO: optional zip compression! -void FBX::Node::WritePropertyNode( +void FBX::Node::WritePropertyNodeBinary( const std::string& name, const std::vector& v, Assimp::StreamWriterLE& s ){ - Node node(name); - node.Begin(s); + FBX::Node node(name); + node.BeginBinary(s); s.PutU1('d'); s.PutU4(uint32_t(v.size())); // number of elements s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(uint32_t(v.size()) * 8); // data size for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); } - node.EndProperties(s, 1); - node.End(s, false); + node.EndPropertiesBinary(s, 1); + node.EndBinary(s, false); } -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. +// binary property node from vector of int32_t // TODO: optional zip compression! -void FBX::Node::WritePropertyNode( +void FBX::Node::WritePropertyNodeBinary( const std::string& name, const std::vector& v, Assimp::StreamWriterLE& s ){ - Node node(name); - node.Begin(s); + FBX::Node node(name); + node.BeginBinary(s); s.PutU1('i'); s.PutU4(uint32_t(v.size())); // number of elements s.PutU4(0); // no encoding (1 would be zip-compressed) s.PutU4(uint32_t(v.size()) * 4); // data size for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); } - node.EndProperties(s, 1); - node.End(s, false); + node.EndPropertiesBinary(s, 1); + node.EndBinary(s, false); } +// public static member functions + +// convenience function to create and write a property node, +// holding a single property which is an array of values. +// does not copy the data, so is efficient for large arrays. +void FBX::Node::WritePropertyNode( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + bool binary, int indent +){ + if (binary) { + FBX::Node::WritePropertyNodeBinary(name, v, s); + } else { + FBX::Node::WritePropertyNodeAscii(name, v, s, indent); + } +} + +// convenience function to create and write a property node, +// holding a single property which is an array of values. +// does not copy the data, so is efficient for large arrays. +void FBX::Node::WritePropertyNode( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + bool binary, int indent +){ + if (binary) { + FBX::Node::WritePropertyNodeBinary(name, v, s); + } else { + FBX::Node::WritePropertyNodeAscii(name, v, s, indent); + } +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportNode.h b/code/FBXExportNode.h index 58d3d14ee..5ddd8c77b 100644 --- a/code/FBXExportNode.h +++ b/code/FBXExportNode.h @@ -142,19 +142,48 @@ public: // support specifically for dealing with Properties70 nodes public: // member functions for writing data to a file or stream - // write the full node as binary data to the given file or stream - void Dump(std::shared_ptr outfile); - void Dump(Assimp::StreamWriterLE &s); + // write the full node to the given file or stream + void Dump( + std::shared_ptr outfile, + bool binary, int indent + ); + void Dump(Assimp::StreamWriterLE &s, bool binary, int indent); // these other functions are for writing data piece by piece. // they must be used carefully. // for usage examples see FBXExporter.cpp. - void Begin(Assimp::StreamWriterLE &s); - void DumpProperties(Assimp::StreamWriterLE& s); - void EndProperties(Assimp::StreamWriterLE &s); - void EndProperties(Assimp::StreamWriterLE &s, size_t num_properties); - void DumpChildren(Assimp::StreamWriterLE& s); - void End(Assimp::StreamWriterLE &s, bool has_children); + void Begin(Assimp::StreamWriterLE &s, bool binary, int indent); + void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent); + void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent); + void EndProperties( + Assimp::StreamWriterLE &s, bool binary, int indent, + size_t num_properties + ); + void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent); + void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent); + void End( + Assimp::StreamWriterLE &s, bool binary, int indent, + bool has_children + ); + +private: // internal functions used for writing + + void DumpBinary(Assimp::StreamWriterLE &s); + void DumpAscii(Assimp::StreamWriterLE &s, int indent); + void DumpAscii(std::ostream &s, int indent); + + void BeginBinary(Assimp::StreamWriterLE &s); + void DumpPropertiesBinary(Assimp::StreamWriterLE& s); + void EndPropertiesBinary(Assimp::StreamWriterLE &s); + void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties); + void DumpChildrenBinary(Assimp::StreamWriterLE& s); + void EndBinary(Assimp::StreamWriterLE &s, bool has_children); + + void BeginAscii(std::ostream &s, int indent); + void DumpPropertiesAscii(std::ostream &s, int indent); + void BeginChildrenAscii(std::ostream &s, int indent); + void DumpChildrenAscii(std::ostream &s, int indent); + void EndAscii(std::ostream &s, int indent, bool has_children); private: // data used for binary dumps size_t start_pos; // starting position in stream @@ -169,11 +198,12 @@ public: // static member functions static void WritePropertyNode( const std::string& name, const T value, - Assimp::StreamWriterLE& s + Assimp::StreamWriterLE& s, + bool binary, int indent ) { FBX::Property p(value); FBX::Node node(name, p); - node.Dump(s); + node.Dump(s, binary, indent); } // convenience function to create and write a property node, @@ -182,7 +212,8 @@ public: // static member functions static void WritePropertyNode( const std::string& name, const std::vector& v, - Assimp::StreamWriterLE& s + Assimp::StreamWriterLE& s, + bool binary, int indent ); // convenience function to create and write a property node, @@ -191,8 +222,34 @@ public: // static member functions static void WritePropertyNode( const std::string& name, const std::vector& v, + Assimp::StreamWriterLE& s, + bool binary, int indent + ); + +private: // static helper functions + static void WritePropertyNodeAscii( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + int indent + ); + static void WritePropertyNodeAscii( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + int indent + ); + static void WritePropertyNodeBinary( + const std::string& name, + const std::vector& v, Assimp::StreamWriterLE& s ); + static void WritePropertyNodeBinary( + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s + ); + }; diff --git a/code/FBXExportProperty.cpp b/code/FBXExportProperty.cpp index e139bb95a..431750274 100644 --- a/code/FBXExportProperty.cpp +++ b/code/FBXExportProperty.cpp @@ -48,7 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include // stringstream +#include +#include +#include // ostringstream // constructors for single element properties @@ -164,18 +166,18 @@ size_t FBX::Property::size() } } -void FBX::Property::Dump(Assimp::StreamWriterLE &s) +void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s) { s.PutU1(type); - uint8_t* d; + uint8_t* d = data.data(); size_t N; switch (type) { - case 'C': s.PutU1(*(reinterpret_cast(data.data()))); return; - case 'Y': s.PutI2(*(reinterpret_cast(data.data()))); return; - case 'I': s.PutI4(*(reinterpret_cast(data.data()))); return; - case 'F': s.PutF4(*(reinterpret_cast(data.data()))); return; - case 'D': s.PutF8(*(reinterpret_cast(data.data()))); return; - case 'L': s.PutI8(*(reinterpret_cast(data.data()))); return; + case 'C': s.PutU1(*(reinterpret_cast(d))); return; + case 'Y': s.PutI2(*(reinterpret_cast(d))); return; + case 'I': s.PutI4(*(reinterpret_cast(d))); return; + case 'F': s.PutF4(*(reinterpret_cast(d))); return; + case 'D': s.PutF8(*(reinterpret_cast(d))); return; + case 'L': s.PutI8(*(reinterpret_cast(d))); return; case 'S': case 'R': s.PutU4(uint32_t(data.size())); @@ -187,7 +189,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s) s.PutU4(0); // no encoding (1 would be zip-compressed) // TODO: compress if large? s.PutU4(uint32_t(data.size())); // data size - d = data.data(); for (size_t i = 0; i < N; ++i) { s.PutI4((reinterpret_cast(d))[i]); } @@ -198,7 +199,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s) s.PutU4(0); // no encoding (1 would be zip-compressed) // TODO: compress if large? s.PutU4(uint32_t(data.size())); // data size - d = data.data(); for (size_t i = 0; i < N; ++i) { s.PutI8((reinterpret_cast(d))[i]); } @@ -209,7 +209,6 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s) s.PutU4(0); // no encoding (1 would be zip-compressed) // TODO: compress if large? s.PutU4(uint32_t(data.size())); // data size - d = data.data(); for (size_t i = 0; i < N; ++i) { s.PutF4((reinterpret_cast(d))[i]); } @@ -220,18 +219,146 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s) s.PutU4(0); // no encoding (1 would be zip-compressed) // TODO: compress if large? s.PutU4(uint32_t(data.size())); // data size - d = data.data(); for (size_t i = 0; i < N; ++i) { s.PutF8((reinterpret_cast(d))[i]); } return; default: - std::stringstream err; + std::ostringstream err; err << "Tried to dump property with invalid type '"; err << type << "'!"; throw DeadlyExportError(err.str()); } } +void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent) +{ + std::ostringstream ss; + ss.imbue(std::locale::classic()); + ss.precision(15); // this seems to match official FBX SDK exports + DumpAscii(ss, indent); + outstream.PutString(ss.str()); +} + +void FBX::Property::DumpAscii(std::ostream& s, int indent) +{ + // no writing type... or anything. just shove it into the stream. + uint8_t* d = data.data(); + size_t N; + size_t swap = data.size(); + size_t count = 0; + switch (type) { + case 'C': + if (*(reinterpret_cast(d))) { s << 'T'; } + else { s << 'F'; } + return; + case 'Y': s << *(reinterpret_cast(d)); return; + case 'I': s << *(reinterpret_cast(d)); return; + case 'F': s << *(reinterpret_cast(d)); return; + case 'D': s << *(reinterpret_cast(d)); return; + case 'L': s << *(reinterpret_cast(d)); return; + case 'S': + // first search to see if it has "\x00\x01" in it - + // which separates fields which are reversed in the ascii version. + // yeah. + // FBX, yeah. + for (size_t i = 0; i < data.size(); ++i) { + if (data[i] == '\0') { + swap = i; + break; + } + } + case 'R': + s << '"'; + // we might as well check this now, + // probably it will never happen + for (size_t i = 0; i < data.size(); ++i) { + char c = data[i]; + if (c == '"') { + throw runtime_error("can't handle quotes in property string"); + } + } + // first write the SWAPPED member (if any) + for (size_t i = swap + 2; i < data.size(); ++i) { + char c = data[i]; + s << c; + } + // then a separator + if (swap != data.size()) { + s << "::"; + } + // then the initial member + for (size_t i = 0; i < swap; ++i) { + char c = data[i]; + s << c; + } + s << '"'; + return; + case 'i': + N = data.size() / 4; // number of elements + s << '*' << N << " {\n"; + for (int i = 0; i < indent + 1; ++i) { s << '\t'; } + s << "a: "; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { s << ','; } + if (count++ > 120) { s << '\n'; count = 0; } + s << (reinterpret_cast(d))[i]; + } + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << "} "; + return; + case 'l': + N = data.size() / 8; + s << '*' << N << " {\n"; + for (int i = 0; i < indent + 1; ++i) { s << '\t'; } + s << "a: "; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { s << ','; } + if (count++ > 120) { s << '\n'; count = 0; } + s << (reinterpret_cast(d))[i]; + } + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << "} "; + return; + case 'f': + N = data.size() / 4; + s << '*' << N << " {\n"; + for (int i = 0; i < indent + 1; ++i) { s << '\t'; } + s << "a: "; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { s << ','; } + if (count++ > 120) { s << '\n'; count = 0; } + s << (reinterpret_cast(d))[i]; + } + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << "} "; + return; + case 'd': + N = data.size() / 8; + s << '*' << N << " {\n"; + for (int i = 0; i < indent + 1; ++i) { s << '\t'; } + s << "a: "; + // set precision to something that can handle doubles + s.precision(15); + for (size_t i = 0; i < N; ++i) { + if (i > 0) { s << ','; } + if (count++ > 120) { s << '\n'; count = 0; } + s << (reinterpret_cast(d))[i]; + } + s << '\n'; + for (int i = 0; i < indent; ++i) { s << '\t'; } + s << "} "; + return; + default: + std::ostringstream err; + err << "Tried to dump property with invalid type '"; + err << type << "'!"; + throw runtime_error(err.str()); + } +} + #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportProperty.h b/code/FBXExportProperty.h index 40a020688..cb3b0113f 100644 --- a/code/FBXExportProperty.h +++ b/code/FBXExportProperty.h @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include // is_void namespace FBX { @@ -113,7 +114,10 @@ public: size_t size(); // write this property node as binary data to the given stream - void Dump(Assimp::StreamWriterLE &s); + void DumpBinary(Assimp::StreamWriterLE &s); + void DumpAscii(Assimp::StreamWriterLE &s, int indent=0); + void DumpAscii(std::ostream &s, int indent=0); + // note: make sure the ostream is in classic "C" locale private: char type; diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index 46782cc2e..e8846be08 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -66,7 +66,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include // endl // RESOURCES: // https://code.blender.org/2013/08/fbx-binary-file-format-specification/ @@ -89,6 +88,8 @@ namespace FBX { "\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e"; const std::string FOOT_MAGIC = "\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b"; + const std::string COMMENT_UNDERLINE = + ";------------------------------------------------------------------"; } using namespace Assimp; @@ -115,7 +116,7 @@ namespace Assimp { // --------------------------------------------------------------------- // Worker function for exporting a scene to ASCII FBX. // Prototyped and registered in Exporter.cpp - /*void ExportSceneFBXA ( + void ExportSceneFBXA ( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, @@ -126,7 +127,7 @@ namespace Assimp { // perform ascii export exporter.ExportAscii(pFile, pIOSystem); - }*/ // TODO + } } // end of namespace Assimp @@ -194,27 +195,43 @@ void FBXExporter::ExportAscii ( ); } - // this isn't really necessary, - // but the Autodesk FBX SDK puts a similar comment at the top of the file. - // Theirs declares that the file copyright is owned by Autodesk... - std::stringstream head; - using std::endl; - head << "; FBX " << EXPORT_VERSION_STR << " project file" << endl; - head << "; Created by the Open Asset Import Library (Assimp)" << endl; - head << "; http://assimp.org" << endl; - head << "; -------------------------------------------------" << endl; - head << endl; - const std::string ascii_header = head.str(); - outfile->Write(ascii_header.c_str(), ascii_header.size(), 1); + // write the ascii header + WriteAsciiHeader(); // write all the sections WriteAllNodes(); + // make sure the file ends with a newline. + // note: if the file is opened in text mode, + // this should do the right cross-platform thing. + outfile->Write("\n", 1, 1); + // explicitly release file pointer, // so we don't have to rely on class destruction. outfile.reset(); } +void FBXExporter::WriteAsciiHeader() +{ + // basically just a comment at the top of the file + std::stringstream head; + head << "; FBX " << EXPORT_VERSION_STR << " project file\n"; + head << "; Created by the Open Asset Import Library (Assimp)\n"; + head << "; http://assimp.org\n"; + head << "; -------------------------------------------------\n"; + const std::string ascii_header = head.str(); + outfile->Write(ascii_header.c_str(), ascii_header.size(), 1); +} + +void FBXExporter::WriteAsciiSectionHeader(const std::string& title) +{ + StreamWriterLE outstream(outfile); + std::stringstream s; + s << "\n\n; " << title << '\n'; + s << FBX::COMMENT_UNDERLINE << "\n"; + outstream.PutString(s.str()); +} + void FBXExporter::WriteBinaryHeader() { // first a specific sequence of 23 bytes, always the same @@ -294,28 +311,39 @@ void FBXExporter::WriteAllNodes () //FBXHeaderExtension top-level node void FBXExporter::WriteHeaderExtension () { + if (!binary) { + // no title, follows directly from the top comment + } FBX::Node n("FBXHeaderExtension"); StreamWriterLE outstream(outfile); + int indent = 0; // begin node - n.Begin(outstream); + n.Begin(outstream, binary, indent); // write properties // (none) // finish properties - n.EndProperties(outstream, 0); + n.EndProperties(outstream, binary, indent, 0); + + // begin children + n.BeginChildren(outstream, binary, indent); + + indent = 1; // write child nodes FBX::Node::WritePropertyNode( - "FBXHeaderVersion", int32_t(1003), outstream + "FBXHeaderVersion", int32_t(1003), outstream, binary, indent ); FBX::Node::WritePropertyNode( - "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream - ); - FBX::Node::WritePropertyNode( - "EncryptionType", int32_t(0), outstream + "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent ); + if (binary) { + FBX::Node::WritePropertyNode( + "EncryptionType", int32_t(0), outstream, binary, indent + ); + } FBX::Node CreationTimeStamp("CreationTimeStamp"); time_t rawtime; @@ -329,36 +357,50 @@ void FBXExporter::WriteHeaderExtension () CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min)); CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec)); CreationTimeStamp.AddChild("Millisecond", int32_t(0)); - CreationTimeStamp.Dump(outstream); + CreationTimeStamp.Dump(outstream, binary, indent); std::stringstream creator; creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision(); - FBX::Node::WritePropertyNode("Creator", creator.str(), outstream); + FBX::Node::WritePropertyNode( + "Creator", creator.str(), outstream, binary, indent + ); - FBX::Node sceneinfo("SceneInfo"); + //FBX::Node sceneinfo("SceneInfo"); //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo"); // not sure if any of this is actually needed, // so just write an empty node for now. - sceneinfo.Dump(outstream); + //sceneinfo.Dump(outstream, binary, indent); + + indent = 0; // finish node - n.End(outstream, true); + n.End(outstream, binary, indent, true); // that's it for FBXHeaderExtension... + if (!binary) { return; } // but binary files also need top-level FileID, CreationTime, Creator: std::vector raw(GENERIC_FILEID.size()); for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) { raw[i] = uint8_t(GENERIC_FILEID[i]); } - FBX::Node::WritePropertyNode("FileId", raw, outstream); - FBX::Node::WritePropertyNode("CreationTime", GENERIC_CTIME, outstream); - FBX::Node::WritePropertyNode("Creator", creator.str(), outstream); + FBX::Node::WritePropertyNode( + "FileId", raw, outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "CreationTime", GENERIC_CTIME, outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "Creator", creator.str(), outstream, binary, indent + ); } void FBXExporter::WriteGlobalSettings () { + if (!binary) { + // no title, follows directly from the header extension + } FBX::Node gs("GlobalSettings"); gs.AddChild("Version", int32_t(1000)); @@ -385,11 +427,15 @@ void FBXExporter::WriteGlobalSettings () p.AddP70int("CurrentTimeMarker", -1); gs.AddChild(p); - gs.Dump(outfile); + gs.Dump(outfile, binary, 0); } void FBXExporter::WriteDocuments () { + if (!binary) { + WriteAsciiSectionHeader("Documents Description"); + } + // not sure what the use of multiple documents would be, // or whether any end-application supports it FBX::Node docs("Documents"); @@ -411,16 +457,19 @@ void FBXExporter::WriteDocuments () doc.AddChild("RootNode", int64_t(0)); docs.AddChild(doc); - docs.Dump(outfile); + docs.Dump(outfile, binary, 0); } void FBXExporter::WriteReferences () { + if (!binary) { + WriteAsciiSectionHeader("Document References"); + } // always empty for now. // not really sure what this is for. FBX::Node n("References"); n.force_has_children = true; - n.Dump(outfile); + n.Dump(outfile, binary, 0); } @@ -469,9 +518,6 @@ size_t count_images(const aiScene* scene) { } } } - //for (auto &s : images) { - // std::cout << "found image: " << s << std::endl; - //} return images.size(); } @@ -511,6 +557,11 @@ void FBXExporter::WriteDefinitions () // determining how many of each type of object there are // and specifying the base properties to use when otherwise unspecified. + // ascii section header + if (!binary) { + WriteAsciiSectionHeader("Object definitions"); + } + // we need to count the objects int32_t count; int32_t total_count = 0; @@ -890,7 +941,7 @@ void FBXExporter::WriteDefinitions () defs.AddChild("Version", int32_t(100)); defs.AddChild("Count", int32_t(total_count)); for (auto &n : object_nodes) { defs.AddChild(n); } - defs.Dump(outfile); + defs.Dump(outfile, binary, 0); } @@ -936,14 +987,20 @@ int64_t to_ktime(double ticks, const aiAnimation* anim) { void FBXExporter::WriteObjects () { + if (!binary) { + WriteAsciiSectionHeader("Object properties"); + } // numbers should match those given in definitions! make sure to check StreamWriterLE outstream(outfile); FBX::Node object_node("Objects"); - object_node.Begin(outstream); - object_node.EndProperties(outstream); + int indent = 0; + object_node.Begin(outstream, binary, indent); + object_node.EndProperties(outstream, binary, indent); + object_node.BeginChildren(outstream, binary, indent); // geometry (aiMesh) mesh_uids.clear(); + indent = 1; for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { // it's all about this mesh aiMesh* m = mScene->mMeshes[mi]; @@ -955,9 +1012,11 @@ void FBXExporter::WriteObjects () n.AddProperty(uid); n.AddProperty(FBX::SEPARATOR + "Geometry"); n.AddProperty("Mesh"); - n.Begin(outstream); - n.DumpProperties(outstream); - n.EndProperties(outstream); + n.Begin(outstream, binary, indent); + n.DumpProperties(outstream, binary, indent); + n.EndProperties(outstream, binary, indent); + n.BeginChildren(outstream, binary, indent); + indent = 2; // output vertex data - each vertex should be unique (probably) std::vector flattened_vertices; @@ -981,7 +1040,7 @@ void FBXExporter::WriteObjects () } } FBX::Node::WritePropertyNode( - "Vertices", flattened_vertices, outstream + "Vertices", flattened_vertices, outstream, binary, indent ); // output polygon data as a flattened array of vertex indices. @@ -997,30 +1056,38 @@ void FBXExporter::WriteObjects () ); } FBX::Node::WritePropertyNode( - "PolygonVertexIndex", polygon_data, outstream + "PolygonVertexIndex", polygon_data, outstream, binary, indent ); // here could be edges but they're insane. // it's optional anyway, so let's ignore it. FBX::Node::WritePropertyNode( - "GeometryVersion", int32_t(124), outstream + "GeometryVersion", int32_t(124), outstream, binary, indent ); // normals, if any if (m->HasNormals()) { FBX::Node normals("LayerElementNormal", int32_t(0)); - normals.Begin(outstream); - normals.DumpProperties(outstream); - normals.EndProperties(outstream); - FBX::Node::WritePropertyNode("Version", int32_t(101), outstream); - FBX::Node::WritePropertyNode("Name", "", outstream); + normals.Begin(outstream, binary, indent); + normals.DumpProperties(outstream, binary, indent); + normals.EndProperties(outstream, binary, indent); + normals.BeginChildren(outstream, binary, indent); + indent = 3; FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", outstream + "Version", int32_t(101), outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "Name", "", outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "MappingInformationType", "ByPolygonVertex", + outstream, binary, indent ); // TODO: vertex-normals or indexed normals when appropriate FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", outstream + "ReferenceInformationType", "Direct", + outstream, binary, indent ); std::vector normal_data; normal_data.reserve(3 * polygon_data.size()); @@ -1033,10 +1100,13 @@ void FBXExporter::WriteObjects () normal_data.push_back(n.z); } } - FBX::Node::WritePropertyNode("Normals", normal_data, outstream); + FBX::Node::WritePropertyNode( + "Normals", normal_data, outstream, binary, indent + ); // note: version 102 has a NormalsW also... not sure what it is, // so we can stick with version 101 for now. - normals.End(outstream, true); + indent = 2; + normals.End(outstream, binary, indent, true); } // uvs, if any @@ -1057,18 +1127,26 @@ void FBXExporter::WriteObjects () DefaultLogger::get()->warn(err.str()); } FBX::Node uv("LayerElementUV", int32_t(uvi)); - uv.Begin(outstream); - uv.DumpProperties(outstream); - uv.EndProperties(outstream); - FBX::Node::WritePropertyNode("Version", int32_t(101), outstream); + uv.Begin(outstream, binary, indent); + uv.DumpProperties(outstream, binary, indent); + uv.EndProperties(outstream, binary, indent); + uv.BeginChildren(outstream, binary, indent); + indent = 3; + FBX::Node::WritePropertyNode( + "Version", int32_t(101), outstream, binary, indent + ); // it doesn't seem like assimp keeps the uv map name, // so just leave it blank. - FBX::Node::WritePropertyNode("Name", "", outstream); FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", outstream + "Name", "", outstream, binary, indent ); FBX::Node::WritePropertyNode( - "ReferenceInformationType", "IndexToDirect", outstream + "MappingInformationType", "ByPolygonVertex", + outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "ReferenceInformationType", "IndexToDirect", + outstream, binary, indent ); std::vector uv_data; @@ -1093,9 +1171,14 @@ void FBXExporter::WriteObjects () } } } - FBX::Node::WritePropertyNode("UV", uv_data, outstream); - FBX::Node::WritePropertyNode("UVIndex", uv_indices, outstream); - uv.End(outstream, true); + FBX::Node::WritePropertyNode( + "UV", uv_data, outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "UVIndex", uv_indices, outstream, binary, indent + ); + indent = 2; + uv.End(outstream, binary, indent, true); } // i'm not really sure why this material section exists, @@ -1108,7 +1191,7 @@ void FBXExporter::WriteObjects () mat.AddChild("ReferenceInformationType", "IndexToDirect"); std::vector mat_indices = {0}; mat.AddChild("Materials", mat_indices); - mat.Dump(outstream); + mat.Dump(outstream, binary, indent); // finally we have the layer specifications, // which select the normals / UV set / etc to use. @@ -1127,10 +1210,11 @@ void FBXExporter::WriteObjects () le.AddChild("Type", "LayerElementUV"); le.AddChild("TypedIndex", int32_t(0)); layer.AddChild(le); - layer.Dump(outstream); + layer.Dump(outstream, binary, indent); // finish the node record - n.End(outstream, true); + indent = 1; + n.End(outstream, binary, indent, true); } // aiMaterial @@ -1274,7 +1358,7 @@ void FBXExporter::WriteObjects () n.AddChild(p); - n.Dump(outstream); + n.Dump(outstream, binary, indent); } // we need to look up all the images we're using, @@ -1322,7 +1406,7 @@ void FBXExporter::WriteObjects () n.AddChild("UseMipMap", int32_t(0)); n.AddChild("Filename", path); n.AddChild("RelativeFilename", path); - n.Dump(outstream); + n.Dump(outstream, binary, indent); } // Textures @@ -1441,7 +1525,7 @@ void FBXExporter::WriteObjects () tnode.AddChild( "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0) ); - tnode.Dump(outstream); + tnode.Dump(outstream, binary, indent); } } @@ -1594,7 +1678,7 @@ void FBXExporter::WriteObjects () // "acuracy"... this is not a typo.... dnode.AddChild("Link_DeformAcuracy", double(50)); dnode.AddChild("SkinningType", "Linear"); // TODO: other modes? - dnode.Dump(outstream); + dnode.Dump(outstream, binary, indent); // connect it connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); @@ -1738,7 +1822,7 @@ void FBXExporter::WriteObjects () // there's not really any way around this at the moment. // done - sdnode.Dump(outstream); + sdnode.Dump(outstream, binary, indent); // lastly, connect to the parent deformer connections.emplace_back( @@ -1856,7 +1940,7 @@ void FBXExporter::WriteObjects () } // now write it - bpnode.Dump(outstream); + bpnode.Dump(outstream, binary, indent); }*/ // TODO: cameras, lights @@ -1916,7 +2000,7 @@ void FBXExporter::WriteObjects () // this node absurdly always pretends it has children // (in this case it does, but just in case...) asnode.force_has_children = true; - asnode.Dump(outstream); + asnode.Dump(outstream, binary, indent); // note: animation stacks are not connected to anything } @@ -1931,7 +2015,7 @@ void FBXExporter::WriteObjects () // this node absurdly always pretends it has children alnode.force_has_children = true; - alnode.Dump(outstream); + alnode.Dump(outstream, binary, indent); // connect to the relevant animstack connections.emplace_back( @@ -2048,7 +2132,8 @@ void FBXExporter::WriteObjects () } } - object_node.End(outstream, true); + indent = 0; + object_node.End(outstream, binary, indent, true); } // convenience map of magic node name strings to FBX properties, @@ -2074,13 +2159,14 @@ const std::map> transform_types = { }; // write a single model node to the stream -void WriteModelNode( +void FBXExporter::WriteModelNode( StreamWriterLE& outstream, + bool binary, const aiNode* node, int64_t node_uid, const std::string& type, const std::vector>& transform_chain, - TransformInheritance inherit_type=TransformInheritance_RSrs + TransformInheritance inherit_type ){ const aiVector3D zero = {0, 0, 0}; const aiVector3D one = {1, 1, 1}; @@ -2148,7 +2234,7 @@ void WriteModelNode( m.AddChild("Shading", Property(true)); m.AddChild("Culling", Property("CullingOff")); - m.Dump(outstream); + m.Dump(outstream, binary, 1); } // wrapper for WriteModelNodes to create and pass a blank transform chain @@ -2249,9 +2335,13 @@ void FBXExporter::WriteModelNodes( node_uid ); // write model node - WriteModelNode(outstream, node, node_uid, "Mesh", transform_chain); + WriteModelNode( + outstream, binary, node, node_uid, "Mesh", transform_chain + ); } else if (limbnodes.count(node)) { - WriteModelNode(outstream, node, node_uid, "LimbNode", transform_chain); + WriteModelNode( + outstream, binary, node, node_uid, "LimbNode", transform_chain + ); // we also need to write a nodeattribute to mark it as a skeleton int64_t node_attribute_uid = generate_uid(); FBX::Node na("NodeAttribute"); @@ -2259,12 +2349,14 @@ void FBXExporter::WriteModelNodes( node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode" ); na.AddChild("TypeFlags", Property("Skeleton")); - na.Dump(outstream); + na.Dump(outstream, binary, 1); // and connect them connections.emplace_back("C", "OO", node_attribute_uid, node_uid); } else { // generate a null node so we can add children to it - WriteModelNode(outstream, node, node_uid, "Null", transform_chain); + WriteModelNode( + outstream, binary, node, node_uid, "Null", transform_chain + ); } // if more than one child mesh, make nodes for each mesh @@ -2296,7 +2388,7 @@ void FBXExporter::WriteModelNodes( FBX::Node p("Properties70"); p.AddP70enum("InheritType", 1); m.AddChild(p); - m.Dump(outstream); + m.Dump(outstream, binary, 1); } } @@ -2325,7 +2417,7 @@ void FBXExporter::WriteAnimationCurveNode( p.AddP70numberA("d|Y", default_value.y); p.AddP70numberA("d|Z", default_value.z); n.AddChild(p); - n.Dump(outstream); + n.Dump(outstream, binary, 1); // connect to layer this->connections.emplace_back("C", "OO", uid, layer_uid); // connect to bone @@ -2356,7 +2448,7 @@ void FBXExporter::WriteAnimationCurve( "KeyAttrRefCount", std::vector{static_cast(times.size())} ); - n.Dump(outstream); + n.Dump(outstream, binary, 1); this->connections.emplace_back( "C", "OP", curve_uid, curvenode_uid, property_link ); @@ -2367,13 +2459,18 @@ void FBXExporter::WriteConnections () { // we should have completed the connection graph already, // so basically just dump it here + if (!binary) { + WriteAsciiSectionHeader("Object connections"); + } + // TODO: comments with names in the ascii version FBX::Node conn("Connections"); StreamWriterLE outstream(outfile); - conn.Begin(outstream); + conn.Begin(outstream, binary, 0); + conn.BeginChildren(outstream, binary, 0); for (auto &n : connections) { - n.Dump(outstream); + n.Dump(outstream, binary, 1); } - conn.End(outstream, !connections.empty()); + conn.End(outstream, binary, 0, !connections.empty()); connections.clear(); } diff --git a/code/FBXExporter.h b/code/FBXExporter.h index 553cf60fe..3b9de8acb 100644 --- a/code/FBXExporter.h +++ b/code/FBXExporter.h @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER #include "FBXExportNode.h" // FBX::Node +#include "FBXCommon.h" // FBX::TransformInheritance #include //#include @@ -104,6 +105,9 @@ namespace Assimp void WriteBinaryHeader(); void WriteBinaryFooter(); + // ascii files have a comment at the top + void WriteAsciiHeader(); + // WriteAllNodes does the actual export. // It just calls all the Write
methods below in order. void WriteAllNodes(); @@ -126,6 +130,7 @@ namespace Assimp // WriteTakes(); // deprecated since at least 2015 (fbx 7.4) // helpers + void WriteAsciiSectionHeader(const std::string& title); void WriteModelNodes( Assimp::StreamWriterLE& s, const aiNode* node, @@ -139,6 +144,15 @@ namespace Assimp const std::unordered_set& limbnodes, std::vector>& transform_chain ); + void WriteModelNode( // nor this + StreamWriterLE& s, + bool binary, + const aiNode* node, + int64_t node_uid, + const std::string& type, + const std::vector>& xfm_chain, + FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs + ); void WriteAnimationCurveNode( StreamWriterLE& outstream, int64_t uid, From 0dad1d0c04fdf4ee04bbb81c56a6cc1a5e45873f Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 29 Mar 2018 01:46:59 +0200 Subject: [PATCH 05/30] FBX Export: fix Texture_Alpha_soutce typo. --- code/FBXExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index e8846be08..4db9fc4d9 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -1521,7 +1521,7 @@ void FBXExporter::WriteObjects () tnode.AddChild("RelativeFilename", texture_path); tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0)); tnode.AddChild("ModelUVScaling", double(1.0), double(1.0)); - tnode.AddChild("Texture_Alpha_Soutce", "None"); + tnode.AddChild("Texture_Alpha_Source", "None"); tnode.AddChild( "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0) ); From 4b2120ab5642b8341e350e1d68de86c328b500b0 Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 29 Mar 2018 10:45:23 +0200 Subject: [PATCH 06/30] FBX Export: fix for geometric transform nodes with multiple children. --- code/FBXExporter.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index 4db9fc4d9..f31a98604 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -2258,15 +2258,6 @@ void FBXExporter::WriteModelNodes( // first collapse any expanded transformation chains created by FBX import. std::string node_name(node->mName.C_Str()); if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { - if (node->mNumChildren != 1) { - // this should never happen - std::stringstream err; - err << "FBX transformation node should have exactly 1 child,"; - err << " but " << node->mNumChildren << " found"; - err << " on node \"" << node_name << "\"!"; - throw DeadlyExportError(err.str()); - } - aiNode* next_node = node->mChildren[0]; auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1; std::string type_name = node_name.substr(pos); auto elem = transform_types.find(type_name); @@ -2300,10 +2291,16 @@ void FBXExporter::WriteModelNodes( err << elem->second.second; throw DeadlyExportError(err.str()); } - // now just continue to the next node - WriteModelNodes( - outstream, next_node, parent_uid, limbnodes, transform_chain - ); + // now continue on to any child nodes + for (unsigned i = 0; i < node->mNumChildren; ++i) { + WriteModelNodes( + outstream, + node->mChildren[i], + parent_uid, + limbnodes, + transform_chain + ); + } return; } From 4a4b9cd31bea4a64a85592cb8b8fa5d07863a50d Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 29 Mar 2018 12:38:56 +0200 Subject: [PATCH 07/30] assimp_cmd: prettier and better-compressed node hierarchy. Also removed line and nesting limits. It's better to show all the info than to silently discard some. With the new compressed display, it is far less obtrusive anyway. --- tools/assimp_cmd/Info.cpp | 107 +++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index c4d5fe189..ae858bfe8 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -46,12 +46,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Main.h" +#include +#include +#include + const char* AICMD_MSG_INFO_HELP_E = "assimp info [-r] [-v]\n" "\tPrint basic structure of a 3D model\n" "\t-r,--raw: No postprocessing, do a raw import\n" "\t-v,--verbose: Print verbose info such as node transform data\n"; +const std::string TREE_BRANCH_ASCII = "|-"; +const std::string TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4"; +const std::string TREE_STOP_ASCII = "'-"; +const std::string TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4"; +const std::string TREE_CONTINUE_ASCII = "| "; +const std::string TREE_CONTINUE_UTF8 = "\xe2\x94\x82 "; + +// note: by default this is outputing utf-8 text. +// this is well supported on pretty much any linux terminal. +// if this causes problems on some platform, +// put an #ifdef to use the ascii version for that platform. +const std::string TREE_BRANCH = TREE_BRANCH_UTF8; +const std::string TREE_STOP = TREE_STOP_UTF8; +const std::string TREE_CONTINUE = TREE_CONTINUE_UTF8; + // ----------------------------------------------------------------------------------- unsigned int CountNodes(const aiNode* root) @@ -184,46 +203,77 @@ std::string FindPTypes(const aiScene* scene) } // ----------------------------------------------------------------------------------- -void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline, - unsigned int cline, bool verbose, unsigned int cnest=0) -{ - if (cline++ >= maxline || cnest >= maxnest) { - return; +// Prettily print the node graph to stdout +void PrintHierarchy( + const aiNode* node, + const std::string &indent, + bool verbose, + bool last = false, + bool first = true +){ + // tree visualization + std::string branchchar; + if (first) { branchchar = ""; } + else if (last) { branchchar = TREE_STOP; } // "'-" + else { branchchar = TREE_BRANCH; } // "|-" + + // print the indent and the branch character and the name + std::cout << indent << branchchar << node->mName.C_Str(); + + // if there are meshes attached, indicate this + if (node->mNumMeshes) { + std::cout << " (mesh "; + bool sep = false; + for (size_t i=0; i < node->mNumMeshes; ++i) { + unsigned int mesh_index = node->mMeshes[i]; + if (sep) { std::cout << ", "; } + std::cout << mesh_index; + sep = true; + } + std::cout << ")"; } - for(unsigned int i = 0; i < cnest; ++i) { - printf("-- "); - } - printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes); + // finish the line + std::cout << std::endl; + // in verbose mode, print the transform data as well if (verbose) { - // print the actual transform - //printf(","); + // indent to use + std::string indentadd; + if (last) { indentadd += " "; } + else { indentadd += TREE_CONTINUE; } // "| ".. + if (node->mNumChildren == 0) { indentadd += " "; } + else { indentadd += TREE_CONTINUE; } // .."| " aiVector3D s, r, t; - root->mTransformation.Decompose(s, r, t); + node->mTransformation.Decompose(s, r, t); if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) { - for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } - printf(" S:[%f %f %f]\n", s.x, s.y, s.z); + std::cout << indent << indentadd; + printf(" S:[%f %f %f]\n", s.x, s.y, s.z); } if (r.x || r.y || r.z) { - for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } - printf(" R:[%f %f %f]\n", r.x, r.y, r.z); + std::cout << indent << indentadd; + printf(" R:[%f %f %f]\n", r.x, r.y, r.z); } if (t.x || t.y || t.z) { - for(unsigned int i = 0; i < cnest; ++i) { printf(" "); } - printf(" T:[%f %f %f]\n", t.x, t.y, t.z); + std::cout << indent << indentadd; + printf(" T:[%f %f %f]\n", t.x, t.y, t.z); } } - //printf("\n"); - for (unsigned int i = 0; i < root->mNumChildren; ++i ) { - PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1); - if(i == root->mNumChildren-1) { - for(unsigned int i = 0; i < cnest; ++i) { - printf(" "); - } - printf("<--\n"); - } + // and recurse + std::string nextIndent; + if (first) { nextIndent = indent; } + else if (last) { nextIndent = indent + " "; } + else { nextIndent = indent + TREE_CONTINUE; } // "| " + for (size_t i = 0; i < node->mNumChildren; ++i) { + bool lastone = (i == node->mNumChildren - 1); + PrintHierarchy( + node->mChildren[i], + nextIndent, + verbose, + lastone, + false + ); } } @@ -406,8 +456,7 @@ int Assimp_Info (const char* const* params, unsigned int num) // node hierarchy printf("\nNode hierarchy:\n"); - unsigned int cline=0; - PrintHierarchy(scene->mRootNode,20,1000,cline,verbose); + PrintHierarchy(scene->mRootNode,"",verbose); printf("\n"); return 0; From 39d98784294ed7bfc5473cd5000b4d7cd7760ed4 Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 29 Mar 2018 13:10:41 +0200 Subject: [PATCH 08/30] FBX Export: use ai_snprintf. --- code/FBXExportNode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/FBXExportNode.cpp b/code/FBXExportNode.cpp index 514d5f360..a1171eca8 100644 --- a/code/FBXExportNode.cpp +++ b/code/FBXExportNode.cpp @@ -47,12 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // StreamWriterLE #include // DeadlyExportError #include +#include // ai_snprintf #include #include #include // ostringstream #include // shared_ptr -#include // snprintf // AddP70 helpers... there's no usable pattern here, // so all are defined as separate functions. @@ -442,7 +442,7 @@ void FBX::Node::WritePropertyNodeAscii( int count = 0; for (size_t i = 0; i < v.size(); ++i) { if (i > 0) { s.PutChar(','); } - int len = snprintf(buffer, sizeof(buffer), "%f", v[i]); + int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]); count += len; if (count > 2048) { s.PutChar('\n'); count = 0; } if (len < 0 || len > 31) { @@ -478,7 +478,7 @@ void FBX::Node::WritePropertyNodeAscii( int count = 0; for (size_t i = 0; i < v.size(); ++i) { if (i > 0) { s.PutChar(','); } - int len = snprintf(buffer, sizeof(buffer), "%d", v[i]); + int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]); count += len; if (count > 2048) { s.PutChar('\n'); count = 0; } if (len < 0 || len > 31) { From 070acfbaddc99db506b90667dc3026644561dcd8 Mon Sep 17 00:00:00 2001 From: Tommy Date: Thu, 29 Mar 2018 14:29:02 +0200 Subject: [PATCH 09/30] FBX Export: relax bindpose matrix check slightly. Apparently +/- 1e-5 is too strict. --- code/FBXExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/FBXExporter.cpp b/code/FBXExporter.cpp index f31a98604..c524e3911 100644 --- a/code/FBXExporter.cpp +++ b/code/FBXExporter.cpp @@ -1784,7 +1784,7 @@ void FBXExporter::WriteObjects () // this should be the same as the bone's mOffsetMatrix. // if it's not the same, the skeleton isn't in the bind pose. - const float epsilon = 1e-5f; // some error is to be expected + const float epsilon = 1e-4f; // some error is to be expected bool bone_xform_okay = true; if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) { not_in_bind_pose.insert(b); From 26ac2ffb6c4cb321c3431db57d5ba0958c5f6fa0 Mon Sep 17 00:00:00 2001 From: Alexis Breust Date: Thu, 29 Mar 2018 15:52:05 +0200 Subject: [PATCH 10/30] Not duplicating textures for embedded ones --- code/glTF2Exporter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/code/glTF2Exporter.cpp b/code/glTF2Exporter.cpp index b873d9d22..e146327ea 100644 --- a/code/glTF2Exporter.cpp +++ b/code/glTF2Exporter.cpp @@ -316,11 +316,9 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref& texture, aiTe std::string path = tex.C_Str(); if (path.size() > 0) { - if (path[0] != '*') { - std::map::iterator it = mTexturesByPath.find(path); - if (it != mTexturesByPath.end()) { - texture = mAsset->textures.Get(it->second); - } + std::map::iterator it = mTexturesByPath.find(path); + if (it != mTexturesByPath.end()) { + texture = mAsset->textures.Get(it->second); } if (!texture) { From c97fb99435b80da87cae138fb026f764cc672cf7 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 16:37:39 +0200 Subject: [PATCH 11/30] closes https://github.com/assimp/assimp/issues/1855: fix correction of node names. --- code/FBXConverter.cpp | 118 +++++++++++++++++++----------------------- code/FBXConverter.h | 29 ++++------- 2 files changed, 63 insertions(+), 84 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index f3a908dd4..cf5d42de2 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -61,6 +61,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include namespace Assimp { namespace FBX { @@ -133,9 +135,7 @@ void Converter::ConvertRootNode() { ConvertNodes( 0L, *out->mRootNode ); } - -void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) -{ +void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) { const std::vector& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" ); std::vector nodes; @@ -153,14 +153,14 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa } const Object* const object = con->SourceObject(); - if ( !object ) { + if ( nullptr == object ) { FBXImporter::LogWarn( "failed to convert source object for Model link" ); continue; } const Model* const model = dynamic_cast( object ); - if ( model ) { + if ( nullptr != model ) { nodes_chain.clear(); post_nodes_chain.clear(); @@ -174,7 +174,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa ai_assert( nodes_chain.size() ); - const std::string& original_name = FixNodeName( model->Name() ); + std::string original_name = FixNodeName( model->Name() ); // check if any of the nodes in the chain has the name the fbx node // is supposed to have. If there is none, add another node to @@ -189,7 +189,15 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa } if ( !name_carrier ) { + NodeNameCache::const_iterator it( std::find( mNodeNames.begin(), mNodeNames.end(), original_name ) ); + if ( it != mNodeNames.end() ) { + original_name = original_name + std::string( "001" ); + } + + mNodeNames.push_back( original_name ); nodes_chain.push_back( new aiNode( original_name ) ); + } else { + original_name = nodes_chain.back()->mName.C_Str(); } //setup metadata on newest node @@ -250,11 +258,11 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa ConvertNodes( model->ID(), *last_parent, new_abs_transform ); if ( doc.Settings().readLights ) { - ConvertLights( *model ); + ConvertLights( *model, original_name ); } if ( doc.Settings().readCameras ) { - ConvertCameras( *model ); + ConvertCameras( *model, original_name ); } nodes.push_back( nodes_chain.front() ); @@ -278,34 +286,31 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa } -void Converter::ConvertLights( const Model& model ) -{ +void Converter::ConvertLights( const Model& model, const std::string &orig_name ) { const std::vector& node_attrs = model.GetAttributes(); for( const NodeAttribute* attr : node_attrs ) { const Light* const light = dynamic_cast( attr ); if ( light ) { - ConvertLight( model, *light ); + ConvertLight( *light, orig_name ); } } } -void Converter::ConvertCameras( const Model& model ) -{ +void Converter::ConvertCameras( const Model& model, const std::string &orig_name ) { const std::vector& node_attrs = model.GetAttributes(); for( const NodeAttribute* attr : node_attrs ) { const Camera* const cam = dynamic_cast( attr ); if ( cam ) { - ConvertCamera( model, *cam ); + ConvertCamera( *cam, orig_name ); } } } -void Converter::ConvertLight( const Model& model, const Light& light ) -{ +void Converter::ConvertLight( const Light& light, const std::string &orig_name ) { lights.push_back( new aiLight() ); aiLight* const out_light = lights.back(); - out_light->mName.Set( FixNodeName( model.Name() ) ); + out_light->mName.Set( orig_name ); const float intensity = light.Intensity() / 100.0f; const aiVector3D& col = light.Color(); @@ -378,12 +383,12 @@ void Converter::ConvertLight( const Model& model, const Light& light ) } } -void Converter::ConvertCamera( const Model& model, const Camera& cam ) +void Converter::ConvertCamera( const Camera& cam, const std::string &orig_name ) { cameras.push_back( new aiCamera() ); aiCamera* const out_camera = cameras.back(); - out_camera->mName.Set( FixNodeName( model.Name() ) ); + out_camera->mName.Set( orig_name ); out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); @@ -397,6 +402,31 @@ void Converter::ConvertCamera( const Model& model, const Camera& cam ) out_camera->mClipPlaneFar = cam.FarPlane(); } +static bool HasName( NodeNameCache &cache, const std::string &name ) { + NodeNameCache::const_iterator it( std::find( cache.begin(), cache.end(), name ) ); + return it != cache.end(); + +} +void Converter::GetUniqueName( const std::string &name, std::string uniqueName ) { + if ( !HasName( mNodeNames, name ) ) { + uniqueName = name; + return; + } + + int i( 0 ); + std::string newName; + while ( HasName( mNodeNames, newName ) ) { + ++i; + newName.clear(); + newName += name; + std::stringstream ext; + ext << std::setfill( '0' ) << std::setw( 3 ) << i; + newName += ext.str(); + } + uniqueName = newName; + mNodeNames.push_back( uniqueName ); +} + const char* Converter::NameTransformationComp( TransformationComp comp ) { @@ -738,7 +768,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector // not be guaranteed. ai_assert( NeedsComplexTransformationChain( model ) == is_complex ); - const std::string& name = FixNodeName( model.Name() ); + std::string name = FixNodeName( model.Name() ); // now, if we have more than just Translation, Scaling and Rotation, // we need to generate a full node chain to accommodate for assimp's @@ -786,8 +816,10 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector // else, we can just multiply the matrices together aiNode* nd = new aiNode(); output_nodes.push_back( nd ); + std::string uniqueName; + GetUniqueName( name, uniqueName ); - nd->mName.Set( name ); + nd->mName.Set( uniqueName ); for (const auto &transform : chain) { nd->mTransformation = nd->mTransformation * transform; @@ -2005,50 +2037,6 @@ void Converter::ConvertAnimations() } } -void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name ) { - if ( node_names.find( fixed_name ) == node_names.end() ) { - FBXImporter::LogError( "Cannot rename node " + fixed_name + ", not existing."); - return; - } - - if ( node_names.find( new_name ) != node_names.end() ) { - FBXImporter::LogError( "Cannot rename node " + fixed_name + " to " + new_name +", name already existing." ); - return; - } - - ai_assert( node_names.find( fixed_name ) != node_names.end() ); - ai_assert( node_names.find( new_name ) == node_names.end() ); - - renamed_nodes[ fixed_name ] = new_name; - - const aiString fn( fixed_name ); - - for( aiCamera* cam : cameras ) { - if ( cam->mName == fn ) { - cam->mName.Set( new_name ); - break; - } - } - - for( aiLight* light : lights ) { - if ( light->mName == fn ) { - light->mName.Set( new_name ); - break; - } - } - - for( aiAnimation* anim : animations ) { - for ( unsigned int i = 0; i < anim->mNumChannels; ++i ) { - aiNodeAnim* const na = anim->mChannels[ i ]; - if ( na->mNodeName == fn ) { - na->mNodeName.Set( new_name ); - break; - } - } - } -} - - std::string Converter::FixNodeName( const std::string& name ) { // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if diff --git a/code/FBXConverter.h b/code/FBXConverter.h index 26ba3cb4e..7ae68c5e5 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -68,6 +68,8 @@ namespace FBX { class Document; +using NodeNameCache = std::vector; + /** * Convert a FBX #Document to #aiScene * @param out Empty scene to be populated @@ -117,16 +119,19 @@ private: void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4()); // ------------------------------------------------------------------------------------------------ - void ConvertLights(const Model& model); + void ConvertLights(const Model& model, const std::string &orig_name ); // ------------------------------------------------------------------------------------------------ - void ConvertCameras(const Model& model); + void ConvertCameras(const Model& model, const std::string &orig_name ); // ------------------------------------------------------------------------------------------------ - void ConvertLight(const Model& model, const Light& light); + void ConvertLight( const Light& light, const std::string &orig_name ); // ------------------------------------------------------------------------------------------------ - void ConvertCamera(const Model& model, const Camera& cam); + void ConvertCamera( const Camera& cam, const std::string &orig_name ); + + // ------------------------------------------------------------------------------------------------ + void GetUniqueName( const std::string &name, std::string uniqueName ); // ------------------------------------------------------------------------------------------------ // this returns unified names usable within assimp identifiers (i.e. no space characters - @@ -258,18 +263,6 @@ private: // convert animation data to aiAnimation et al void ConvertAnimations(); - // ------------------------------------------------------------------------------------------------ - // rename a node already partially converted. fixed_name is a string previously returned by - // FixNodeName, new_name specifies the string FixNodeName should return on all further invocations - // which would previously have returned the old value. - // - // this also updates names in node animations, cameras and light sources and is thus slow. - // - // NOTE: the caller is responsible for ensuring that the new name is unique and does - // not collide with any other identifiers. The best way to ensure this is to only - // append to the old name, which is guaranteed to match these requirements. - void RenameNode(const std::string& fixed_name, const std::string& new_name); - // ------------------------------------------------------------------------------------------------ // takes a fbx node name and returns the identifier to be used in the assimp output scene. // the function is guaranteed to provide consistent results over multiple invocations @@ -281,7 +274,6 @@ private: // XXX: better use multi_map .. typedef std::map > NodeMap; - // ------------------------------------------------------------------------------------------------ void ConvertAnimationStack(const AnimationStack& st); @@ -439,12 +431,11 @@ private: typedef std::map NameNameMap; NameNameMap renamed_nodes; + NodeNameCache mNodeNames; double anim_fps; aiScene* const out; const FBX::Document& doc; - - std::vector mLightNames; }; } From 2a5728b4c3149feee04a7becda1704e17cd01f50 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 17:25:29 +0200 Subject: [PATCH 12/30] FBX-Importer: fix usage of deprecated include. --- code/FBXConverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index cf5d42de2..89e0d3edc 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -61,7 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include #include namespace Assimp { From f3cc2f79fccd490c6a2a47e0938d49fb87768fd0 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 17:30:31 +0200 Subject: [PATCH 13/30] FBX-Importer: remove unused lookup table. --- code/FBXConverter.cpp | 6 ++---- code/FBXConverter.h | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 89e0d3edc..9f275b7cb 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2054,8 +2054,7 @@ std::string Converter::FixNodeName( const std::string& name ) } node_names[ temp ] = true; - const NameNameMap::const_iterator rit = renamed_nodes.find( temp ); - return rit == renamed_nodes.end() ? temp : ( *rit ).second; + return temp; } const NodeNameMap::const_iterator it = node_names.find( name ); @@ -2066,8 +2065,7 @@ std::string Converter::FixNodeName( const std::string& name ) } node_names[ name ] = false; - const NameNameMap::const_iterator rit = renamed_nodes.find( name ); - return rit == renamed_nodes.end() ? name : ( *rit ).second; + return name; } void Converter::ConvertAnimationStack( const AnimationStack& st ) diff --git a/code/FBXConverter.h b/code/FBXConverter.h index 7ae68c5e5..83e469e3c 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -428,9 +428,6 @@ private: typedef std::map NodeNameMap; NodeNameMap node_names; - typedef std::map NameNameMap; - NameNameMap renamed_nodes; - NodeNameCache mNodeNames; double anim_fps; From c9bb3592ff8c3866ac0dcc8f2b2089caba06879f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 18:10:29 +0200 Subject: [PATCH 14/30] FBX-Importer: remove unused lookup tables for nodes. --- code/FBXConverter.cpp | 20 +------------------- code/FBXConverter.h | 4 ---- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 9f275b7cb..2c9818a16 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2037,34 +2037,16 @@ void Converter::ConvertAnimations() } } -std::string Converter::FixNodeName( const std::string& name ) -{ +std::string Converter::FixNodeName( const std::string& name ) { // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if // this causes ambiguities, well possible between empty identifiers, // such as "Model::" and ""). Make sure the behaviour is consistent // across multiple calls to FixNodeName(). if ( name.substr( 0, 7 ) == "Model::" ) { std::string temp = name.substr( 7 ); - - const NodeNameMap::const_iterator it = node_names.find( temp ); - if ( it != node_names.end() ) { - if ( !( *it ).second ) { - return FixNodeName( name + "_" ); - } - } - node_names[ temp ] = true; - return temp; } - const NodeNameMap::const_iterator it = node_names.find( name ); - if ( it != node_names.end() ) { - if ( ( *it ).second ) { - return FixNodeName( name + "_" ); - } - } - node_names[ name ] = false; - return name; } diff --git a/code/FBXConverter.h b/code/FBXConverter.h index 83e469e3c..60fd04e2c 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -424,10 +424,6 @@ private: typedef std::map NodeAnimBitMap; NodeAnimBitMap node_anim_chain_bits; - // name -> has had its prefix_stripped? - typedef std::map NodeNameMap; - NodeNameMap node_names; - NodeNameCache mNodeNames; double anim_fps; From dbf32abfb2c3e2d4eff327d4e7dd806ce6b2d043 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 18:51:31 +0200 Subject: [PATCH 15/30] Build: use c++11 in openddl-parser as well. --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0026dcb7f..ffd978562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,8 +138,7 @@ SET (PROJECT_VERSION "${ASSIMP_VERSION}") SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) -# Needed for openddl_parser config, no use of c++11 at this moment -ADD_DEFINITIONS( -DOPENDDL_NO_USE_CPP11 ) +# Enable C++1 globally set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) # Get the current working branch From 417c4fcb457ab8282e8698596cba2de99c604e92 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 18:53:00 +0200 Subject: [PATCH 16/30] Cmake: remove dead code. --- CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd978562..f48fcd773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,14 +191,6 @@ SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPO SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") IF( UNIX ) - # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux - IF( ${OPERATING_SYSTEM} MATCHES "Android") - ELSE() - IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux - #ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 ) - ENDIF() - ENDIF() - # Use GNUInstallDirs for Unix predefined directories INCLUDE(GNUInstallDirs) ENDIF( UNIX ) From 676e1c956561273986a74029915cfdea8ede30a9 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 31 Mar 2018 19:12:53 +0200 Subject: [PATCH 17/30] Cmake: adapt cmake script for VS2017 --- CMakeLists.txt | 108 +++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f48fcd773..83e1be081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,7 @@ EXECUTE_PROCESS( ) IF(NOT GIT_COMMIT_HASH) - SET(GIT_COMMIT_HASH 0) + SET(GIT_COMMIT_HASH 0) ENDIF(NOT GIT_COMMIT_HASH) IF(ASSIMP_DOUBLE_PRECISION) @@ -178,10 +178,10 @@ CONFIGURE_FILE( ) INCLUDE_DIRECTORIES( - ./ - include - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/include + ./ + include + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/include ) LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) @@ -203,13 +203,13 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC - add_compile_options(/MP) - if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") - add_compile_options( /bigobj ) - endif() + ADD_COMPILE_OPTIONS(/MP) + IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") + ADD_COMPILE_OPTIONS( /bigobj ) + ENDIF() # disable "elements of array '' will be default initialized" warning on MSVC2013 IF(MSVC12) - add_compile_options(/wd4351) + ADD_COMPILE_OPTIONS(/wd4351) ENDIF() ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" ) @@ -220,39 +220,39 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() -if (IOS) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") -endif() +IF (IOS) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") +ENDIF() -if (ASSIMP_COVERALLS) - MESSAGE(STATUS "Coveralls enabled") - INCLUDE(Coveralls) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") -endif() +IF (ASSIMP_COVERALLS) + MESSAGE(STATUS "Coveralls enabled") + INCLUDE(Coveralls) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +ENDIF() -if (ASSIMP_WERROR) +IF (ASSIMP_WERROR) MESSAGE(STATUS "Treating warnings as errors") IF (MSVC) - add_compile_options(/WX) + ADD_COMPILE_OPTIONS(/WX) ELSE() SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") ENDIF() -endif() +ENDIF() -if (ASSIMP_ASAN) - MESSAGE(STATUS "AddressSanitizer enabled") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") -endif() +IF (ASSIMP_ASAN) + MESSAGE(STATUS "AddressSanitizer enabled") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") +ENDIF() -if (ASSIMP_UBSAN) - MESSAGE(STATUS "Undefined Behavior sanitizer enabled") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") -endif() +IF (ASSIMP_UBSAN) + MESSAGE(STATUS "Undefined Behavior sanitizer enabled") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") +ENDIF() INCLUDE (FindPkgMacros) INCLUDE (PrecompiledHeader) @@ -285,42 +285,42 @@ ENDIF() IF (NOT TARGET uninstall) # add make uninstall capability CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) - add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ENDIF() # cmake configuration files CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) +INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) FIND_PACKAGE( DirectX ) IF( BUILD_DOCS ) - add_subdirectory(doc) + ADD_SUBDIRECTORY(doc) ENDIF( BUILD_DOCS ) # Look for system installed irrXML IF ( SYSTEM_IRRXML ) - find_package( IrrXML REQUIRED ) + FIND_PACKAGE( IrrXML REQUIRED ) ENDIF( SYSTEM_IRRXML ) # Search for external dependencies, and build them from source if not found # Search for zlib IF ( NOT ASSIMP_BUILD_ZLIB ) - find_package(ZLIB) + FIND_PACKAGE(ZLIB) ENDIF( NOT ASSIMP_BUILD_ZLIB ) IF( NOT ZLIB_FOUND ) - message(STATUS "compiling zlib from souces") + MESSAGE(STATUS "compiling zlib from souces") INCLUDE(CheckIncludeFile) INCLUDE(CheckTypeSize) INCLUDE(CheckFunctionExists) # compile from sources - add_subdirectory(contrib/zlib) + ADD_SUBDIRECTORY(contrib/zlib) SET(ZLIB_FOUND 1) SET(ZLIB_LIBRARIES zlibstatic) SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) -else(NOT ZLIB_FOUND) +ELSE(NOT ZLIB_FOUND) ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) SET(ZLIB_LIBRARIES_LINKED -lz) ENDIF(NOT ZLIB_FOUND) @@ -362,7 +362,9 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes") # pick the correct prebuilt library - IF(MSVC14) + IF(MSVC15) + SET(C4D_LIB_POSTFIX "_2017") + ELSEIF(MSVC14) SET(C4D_LIB_POSTFIX "_2015") ELSEIF(MSVC12) SET(C4D_LIB_POSTFIX "_2013") @@ -403,7 +405,7 @@ ADD_SUBDIRECTORY(contrib) ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( WIN32 AND DirectX_D3DX9_LIBRARY ) - option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} ) + OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} ) IF ( ASSIMP_BUILD_ASSIMP_VIEW ) ADD_SUBDIRECTORY( tools/assimp_view/ ) ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW ) @@ -467,8 +469,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") - string(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") - string(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") + STRING(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") + STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools") SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" ) @@ -498,8 +500,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release") ENDIF() SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources") - include(CPack) - include(DebSourcePPA) + INCLUDE(CPack) + INCLUDE(DebSourcePPA) ENDIF() if(WIN32) @@ -511,14 +513,16 @@ if(WIN32) SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/") ENDIF() - if(MSVC12) + IF(MSVC12) SET(ASSIMP_MSVC_VERSION "vc120") - elseif(MSVC14) + ELSEIF(MSVC14) SET(ASSIMP_MSVC_VERSION "vc140") + ELSEIF(MSVC15) + SET(ASSIMP_MSVC_VERSION "vc141") ENDIF(MSVC12) - if(MSVC12 OR MSVC14) - add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) + IF(MSVC12 OR MSVC14 OR MSVC15 ) + ADD_CUSTOM_TARGET(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) IF(CMAKE_GENERATOR MATCHES "^Visual Studio") ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) @@ -539,5 +543,5 @@ if(WIN32) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) ENDIF() - ENDIF(MSVC12 OR MSVC14) + ENDIF(MSVC12 OR MSVC14 OR MSVC15 ) ENDIF (WIN32) From 04c65ccdcbd6b3f7d55920351648715aedb3557f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 1 Apr 2018 17:16:14 +0200 Subject: [PATCH 18/30] closes https://github.com/assimp/assimp/issues/1831: make config CMAKE_LIBRARY_CONFIG overridable. --- assimp-config.cmake.in | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/assimp-config.cmake.in b/assimp-config.cmake.in index e06cc10ee..5031c8f8d 100644 --- a/assimp-config.cmake.in +++ b/assimp-config.cmake.in @@ -34,36 +34,18 @@ if( MSVC ) else() set(MSVC_PREFIX "vc150") endif() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE) + set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) else() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" FORCE) + set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" ) endif() set( ASSIMP_CXX_FLAGS ) # dynamically linked library -if( WIN32 ) - # for visual studio linking, most of the time boost dlls will be used - set( ASSIMP_CXX_FLAGS " -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB") -endif() set( ASSIMP_LINK_FLAGS "" ) set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX}) set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}@CMAKE_DEBUG_POSTFIX@) -# search for the boost version assimp was compiled with -#set(Boost_USE_MULTITHREAD ON) -#set(Boost_USE_STATIC_LIBS OFF) -#set(Boost_USE_STATIC_RUNTIME OFF) -#find_package(Boost ${ASSIMP_Boost_VERSION} EXACT COMPONENTS thread date_time) -#if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") -# set( ASSIMP_INCLUDE_DIRS "${ASSIMP_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS}) -#else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") -# message(WARNING "Failed to find Boost ${ASSIMP_Boost_VERSION} necessary for assimp") -#endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") - -# the boost version assimp was compiled with -set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@") - # for compatibility with pkg-config set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}") @@ -74,7 +56,6 @@ MARK_AS_ADVANCED( ASSIMP_LINK_FLAGS ASSIMP_INCLUDE_DIRS ASSIMP_LIBRARIES - ASSIMP_Boost_VERSION ASSIMP_CFLAGS_OTHER ASSIMP_LDFLAGS_OTHER ASSIMP_LIBRARY_SUFFIX From 35f4e7101a2ac88e3478156be77dd083fc64257b Mon Sep 17 00:00:00 2001 From: Edward Andrew <=ed.andrew95@gmail.com> Date: Mon, 2 Apr 2018 01:46:14 +0100 Subject: [PATCH 19/30] Fixed issue#1219. CalcTangentsProcess::ProcessMesh. --- code/CalcTangentsProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index cb0117aef..d77d70a5b 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -190,7 +190,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y; float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f; // when t1, t2, t3 in same position in UV space, just use default UV direction. - if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) { + if ( sx * ty == sy * tx ) { sx = 0.0; sy = 1.0; tx = 1.0; ty = 0.0; } From 4d662c42b3f984b68b4fc38c8807abff6ec7622b Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 2 Apr 2018 10:27:05 +0200 Subject: [PATCH 20/30] Add check for SSE2-support. --- code/CMakeLists.txt | 2 ++ code/simd.cpp | 34 ++++++++++++++++++++++++++++++++++ code/simd.h | 5 +++++ test/CMakeLists.txt | 1 + test/unit/utAnim.cpp | 4 +--- 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 code/simd.cpp create mode 100644 code/simd.h diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 7ae1a7e63..d5d05db18 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -186,6 +186,8 @@ SET( Common_SRCS Bitmap.cpp Version.cpp CreateAnimMesh.cpp + simd.h + simd.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) diff --git a/code/simd.cpp b/code/simd.cpp new file mode 100644 index 000000000..e07398156 --- /dev/null +++ b/code/simd.cpp @@ -0,0 +1,34 @@ +#include "simd.h" + +namespace Assimp { + bool CPUSupportsSSE2() { +#if defined(__x86_64__) || defined(_M_X64) + //* x86_64 always has SSE2 instructions */ + return true; +#elif defined(__GNUC__) && defined(i386) + // for GCC x86 we check cpuid + unsigned int d; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=d" ( d ) + :"a" ( 1 ) ); + return ( d & 0x04000000 ) != 0; +#elif (defined(_MSC_VER) && defined(_M_IX86)) + // also check cpuid for MSVC x86 + unsigned int d; + __asm { + xor eax, eax + inc eax + push ebx + cpuid + pop ebx + mov d, edx + } + return ( d & 0x04000000 ) != 0; +#else + return false; +#endif + } +} diff --git a/code/simd.h b/code/simd.h new file mode 100644 index 000000000..d490cbe85 --- /dev/null +++ b/code/simd.h @@ -0,0 +1,5 @@ +#pragma once + +namespace Assimp { + bool CPUSupportsSSE2(); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 049dbcdd2..7c5ff3706 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,6 +53,7 @@ endif() LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib ) SET( COMMON + unit/utSimd.cpp unit/utIOSystem.cpp unit/utIOStreamBuffer.cpp unit/utIssues.cpp diff --git a/test/unit/utAnim.cpp b/test/unit/utAnim.cpp index 04ee8c96d..40c840d7e 100644 --- a/test/unit/utAnim.cpp +++ b/test/unit/utAnim.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2018, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -106,4 +104,4 @@ TEST_F( utAnim, aiAnimationTest ) { ok = false; } EXPECT_TRUE( ok ); -} \ No newline at end of file +} From 7faf638cca1ea5f05680df812dd0445a828460fa Mon Sep 17 00:00:00 2001 From: Andy Maloney Date: Mon, 2 Apr 2018 14:41:02 -0400 Subject: [PATCH 21/30] Add links to some file format info in readme --- Readme.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Readme.md b/Readme.md index 4ee8a0e90..c78a0c1c8 100644 --- a/Readme.md +++ b/Readme.md @@ -35,29 +35,29 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki __Importers__: - 3D -- 3DS -- 3MF +- [3DS](https://en.wikipedia.org/wiki/.3ds) +- [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format) - AC -- AC3D +- [AC3D](https://en.wikipedia.org/wiki/AC3D) - ACC - AMJ - ASE - ASK - B3D -- BLEND (Blender) -- BVH -- COB +- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format)) +- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy) - CMS -- DAE/Collada -- DXF +- COB +- [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA) +- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF) - ENFF -- FBX -- glTF 1.0 + GLB -- glTF 2.0 +- [FBX](https://en.wikipedia.org/wiki/FBX) +- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB +- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0) - HMB - IFC-STEP - IRR / IRRMESH -- LWO +- [LWO](https://en.wikipedia.org/wiki/LightWave_3D) - LWS - LXO - MD2 @@ -70,10 +70,10 @@ __Importers__: - MS3D - NDO - NFF -- OBJ -- OFF -- OGEX -- PLY +- [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) +- [OFF](https://en.wikipedia.org/wiki/OFF_(file_format)) +- [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange) +- [PLY](https://en.wikipedia.org/wiki/PLY_(file_format)) - PMX - PRJ - Q3O @@ -82,19 +82,19 @@ __Importers__: - SCN - SIB - SMD -- STL -- STP +- [STP](https://en.wikipedia.org/wiki/ISO_10303-21) +- [STL](https://en.wikipedia.org/wiki/STL_(file_format)) - TER - UC - VTA - X -- X3D +- [X3D](https://en.wikipedia.org/wiki/X3D) - XGL - ZGL Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): -- C4D (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) +- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) __Exporters__: From 6147a4f50d7dd746b7955b97c00d1f1564342c59 Mon Sep 17 00:00:00 2001 From: James Carthew Date: Wed, 4 Apr 2018 08:08:28 +1000 Subject: [PATCH 22/30] Updated COB importer plugin to flip normals. --- code/COBLoader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/code/COBLoader.cpp b/code/COBLoader.cpp index 793cbfe75..222088cbd 100644 --- a/code/COBLoader.cpp +++ b/code/COBLoader.cpp @@ -47,11 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_COB_IMPORTER #include "COBLoader.h" #include "COBScene.h" - +#include "ConvertToLHProcess.h" #include #include #include - #include #include #include @@ -105,7 +104,7 @@ COBImporter::~COBImporter() bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string& extension = GetExtension(pFile); - if (extension == "cob" || extension == "scn") { + if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") { return true; } @@ -225,6 +224,9 @@ void COBImporter::InternReadFile( const std::string& pFile, } pScene->mRootNode = BuildNodes(*root.get(),scene,pScene); + //flip normals after import + FlipWindingOrderProcess flip; + flip.Execute( pScene ); } // ------------------------------------------------------------------------------------------------ @@ -1299,3 +1301,4 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const #endif + From c232c4bfb328fa6762aecbd258b4d8fd795a1349 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 4 Apr 2018 16:32:18 +0200 Subject: [PATCH 23/30] Add missing file to fix the build. --- test/unit/utSimd.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 test/unit/utSimd.cpp diff --git a/test/unit/utSimd.cpp b/test/unit/utSimd.cpp new file mode 100644 index 000000000..da1b19fce --- /dev/null +++ b/test/unit/utSimd.cpp @@ -0,0 +1,57 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2018, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#include "UnitTestPCH.h" + +#include "simd.h" + +using namespace ::Assimp; + +class utSimd : public ::testing::Test { +protected: + // empty +}; + +TEST_F( utSimd, SSE2SupportedTest ) { + bool isSupported; + + isSupported = CPUSupportsSSE2(); +} From 4254142575019cb567306ce58c310847bd6d5a56 Mon Sep 17 00:00:00 2001 From: James Carthew Date: Thu, 5 Apr 2018 06:37:18 +1000 Subject: [PATCH 24/30] Updated GLView to draw with white lighting after drawCoordSystem(). --- tools/assimp_qt_viewer/glview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp index 5b755d456..d30d0b5de 100644 --- a/tools/assimp_qt_viewer/glview.cpp +++ b/tools/assimp_qt_viewer/glview.cpp @@ -609,6 +609,7 @@ void CGLView::drawCoordSystem() { // Z, -Z qglColor(QColor(Qt::blue)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0); qglColor(QColor(Qt::yellow)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0); + qglColor(QColor(Qt::white)); glEnd(); } From 8cb25328cb4381d4d1d11627b5c6c9444e021cc3 Mon Sep 17 00:00:00 2001 From: James Carthew Date: Thu, 5 Apr 2018 17:50:30 +1000 Subject: [PATCH 25/30] committing all changes. --- code/3DSLoader.cpp | 4 ++-- tools/assimp_qt_viewer/glview.cpp | 29 ++++++++++++++++++++++++++- tools/assimp_qt_viewer/glview.hpp | 11 ++++++++-- tools/assimp_qt_viewer/mainwindow.cpp | 20 ++++++++++++++++++ tools/assimp_qt_viewer/mainwindow.hpp | 4 +++- tools/assimp_qt_viewer/mainwindow.ui | 22 +++++++++++++++++++- 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index 92a64e3d8..bfe2bf6e5 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -71,7 +71,7 @@ static const aiImporterDesc desc = { 0, 0, 0, - "3ds prj" + "3ds prj 3DS PRJ" }; @@ -127,7 +127,7 @@ Discreet3DSImporter::~Discreet3DSImporter() { // Returns whether the class can handle the format of the given file. bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { std::string extension = GetExtension(pFile); - if(extension == "3ds" || extension == "prj" ) { + if(extension == "3ds" || extension == "3DS" || extension == "prj"|| extension == "PRJ" ) { return true; } diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp index d30d0b5de..a9a60a6fc 100644 --- a/tools/assimp_qt_viewer/glview.cpp +++ b/tools/assimp_qt_viewer/glview.cpp @@ -560,6 +560,30 @@ void CGLView::Enable_Textures(const bool pEnable) } } +void CGLView::Enable_Axes(const bool pEnable){ + if(pEnable) + { + this->mAxesEnabled = true; + } + else + { + this->mAxesEnabled = false; + } +} + +void CGLView::Enable_Reload_Textures(const bool pEnable) +{ + if(pEnable) + { + this->mReloadTexturesEnabled = true; +// this->mScene->ImportTextures(this->mScene->pScenePath); + } + else + { + this->mReloadTexturesEnabled = false; + } +} + /********************************************************************/ /*********************** Override functions ************************/ /********************************************************************/ @@ -630,7 +654,10 @@ void CGLView::paintGL() if ( mLightingEnabled ) { glDisable( GL_LIGHTING );///TODO: display list } - drawCoordSystem(); + if (this->mAxesEnabled == true) + { + drawCoordSystem(); + } glDisable(GL_COLOR_MATERIAL); if(mLightingEnabled) glEnable(GL_LIGHTING); diff --git a/tools/assimp_qt_viewer/glview.hpp b/tools/assimp_qt_viewer/glview.hpp index ecd7c6b0f..1c397f13f 100644 --- a/tools/assimp_qt_viewer/glview.hpp +++ b/tools/assimp_qt_viewer/glview.hpp @@ -75,7 +75,9 @@ private: }; public: - + bool mAxesEnabled = true; + // Textures + bool mReloadTexturesEnabled = false; // If true then textures will reload when the window is activated. /// \enum ELightType /// Type of light source. enum class ELightType { Directional, Point, Spot }; @@ -155,7 +157,6 @@ private: GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). // Lighting bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled. - // Textures ///TODO: map is goooood, but not for case when one image can be used in different materials with difference in: texture transformation, targeting of the /// texture (ambient or emission, or even height map), texture properties. QMap mTexture_IDMap;///< Map image filenames to textures ID's. @@ -306,6 +307,12 @@ public: /// \param [in] pEnable - if true then enable textures, false - disable textures. void Enable_Textures(const bool pEnable); + void Enable_Axes(const bool pEnable); + /// \fn void Enable_Textures(const bool pEnable) + /// Control textures drawing. + /// \param [in] pEnable - if true then enable textures, false - disable textures. + void Enable_Reload_Textures(const bool pEnable); + /********************************************************************/ /******************** Lighting control functions ********************/ /********************************************************************/ diff --git a/tools/assimp_qt_viewer/mainwindow.cpp b/tools/assimp_qt_viewer/mainwindow.cpp index acfc8e589..d7d809086 100644 --- a/tools/assimp_qt_viewer/mainwindow.cpp +++ b/tools/assimp_qt_viewer/mainwindow.cpp @@ -48,6 +48,7 @@ QTime time_begin = QTime::currentTime(); ui->cbxLighting->setChecked(true); mGLView->Lighting_Enable(); ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false); ui->cbxTextures->setChecked(true); mGLView->Enable_Textures(true); + ui->cbxReloadTextures->setChecked(true); mGLView->Enable_Reload_Textures(false); // // Fill info labels // @@ -194,6 +195,13 @@ GLfloat step; /********************************************************************/ /********************** Constructor/Destructor **********************/ /********************************************************************/ +bool MainWindow::event(QEvent *e) +{ + if (e->type() == QEvent::WindowActivate && this->mGLView->mReloadTexturesEnabled == true) { + qInfo() << "Window Activated"; + } + return QWidget::event(e); +} MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), @@ -364,6 +372,18 @@ void MainWindow::on_cbxBBox_clicked(bool checked) mGLView->updateGL(); } +void MainWindow::on_cbxDrawAxes_clicked(bool checked) +{ + mGLView->Enable_Axes(checked); + mGLView->updateGL(); +} + +void MainWindow::on_cbxReloadTextures_clicked(bool checked) +{ + mGLView->Enable_Reload_Textures(checked); + mGLView->updateGL(); +} + void MainWindow::on_cbxTextures_clicked(bool checked) { mGLView->Enable_Textures(checked); diff --git a/tools/assimp_qt_viewer/mainwindow.hpp b/tools/assimp_qt_viewer/mainwindow.hpp index 350b37abf..da8a852ac 100644 --- a/tools/assimp_qt_viewer/mainwindow.hpp +++ b/tools/assimp_qt_viewer/mainwindow.hpp @@ -90,7 +90,7 @@ protected: /// \param [in] pEvent - pointer to event data. void keyPressEvent(QKeyEvent* pEvent) override; - + bool event(QEvent*); public: /********************************************************************/ @@ -133,4 +133,6 @@ private slots: void on_lstCamera_clicked(const QModelIndex &index); void on_cbxBBox_clicked(bool checked); void on_cbxTextures_clicked(bool checked); + void on_cbxDrawAxes_clicked(bool checked); + void on_cbxReloadTextures_clicked(bool checked); }; diff --git a/tools/assimp_qt_viewer/mainwindow.ui b/tools/assimp_qt_viewer/mainwindow.ui index 105a470e0..9b139bafd 100644 --- a/tools/assimp_qt_viewer/mainwindow.ui +++ b/tools/assimp_qt_viewer/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 641 - 734 + 778 @@ -501,6 +501,23 @@ + + + + Show Axes + + + true + + + + + + + Live Reload Textures + + + @@ -513,4 +530,7 @@ + + installEventFilter() + From 08ddd5c296589fe398eb851a7aa9f34025f6c5c5 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 6 Apr 2018 10:53:32 +0200 Subject: [PATCH 26/30] Export missig symbols. --- code/simd.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ code/simd.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/code/simd.cpp b/code/simd.cpp index e07398156..9c86cb970 100644 --- a/code/simd.cpp +++ b/code/simd.cpp @@ -1,3 +1,45 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2018, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ #include "simd.h" namespace Assimp { diff --git a/code/simd.h b/code/simd.h index d490cbe85..8fe2bb851 100644 --- a/code/simd.h +++ b/code/simd.h @@ -1,5 +1,51 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2018, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ #pragma once +#include + namespace Assimp { - bool CPUSupportsSSE2(); -} + +bool ASSIMP_API CPUSupportsSSE2(); + +} // Namespace Assimp From d17cf76c8576592572f9a6093648c176df840fa2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 6 Apr 2018 11:16:52 +0200 Subject: [PATCH 27/30] Fix compiler warning in unit test: unused variable. --- test/unit/utSimd.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unit/utSimd.cpp b/test/unit/utSimd.cpp index da1b19fce..33358c0da 100644 --- a/test/unit/utSimd.cpp +++ b/test/unit/utSimd.cpp @@ -54,4 +54,9 @@ TEST_F( utSimd, SSE2SupportedTest ) { bool isSupported; isSupported = CPUSupportsSSE2(); + if ( isSupported ) { + std::cout << "Supported" << std::endl; + } else { + std::cout << "Not supported" << std::endl; + } } From 32b466941beb1d041eaad84cd2be0b697d31fcfb Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 6 Apr 2018 12:01:22 +0200 Subject: [PATCH 28/30] Add missig docs and fix some small review findings. --- code/ScenePrivate.h | 32 ++++++++++----- code/simd.cpp | 54 +++++++++++++------------- code/simd.h | 2 + test/unit/AbstractImportExportBase.cpp | 2 +- 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/code/ScenePrivate.h b/code/ScenePrivate.h index a09d8784b..6a44def2c 100644 --- a/code/ScenePrivate.h +++ b/code/ScenePrivate.h @@ -42,22 +42,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Stuff to deal with aiScene::mPrivate */ +#pragma once #ifndef AI_SCENEPRIVATE_H_INCLUDED #define AI_SCENEPRIVATE_H_INCLUDED #include -namespace Assimp { +namespace Assimp { +// Forward declarations class Importer; struct ScenePrivateData { - ScenePrivateData() - : mOrigImporter() - , mPPStepsApplied() - , mIsCopy() - {} + : mOrigImporter( nullptr ) + , mPPStepsApplied( 0 ) + , mIsCopy( false ) { + // empty + } // Importer that originally loaded the scene though the C-API // If set, this object is owned by this private data instance. @@ -75,14 +77,24 @@ struct ScenePrivateData { }; // Access private data stored in the scene -inline ScenePrivateData* ScenePriv(aiScene* in) { +inline +ScenePrivateData* ScenePriv(aiScene* in) { + ai_assert( nullptr != in ); + if ( nullptr == in ) { + return nullptr; + } return static_cast(in->mPrivate); } -inline const ScenePrivateData* ScenePriv(const aiScene* in) { +inline +const ScenePrivateData* ScenePriv(const aiScene* in) { + ai_assert( nullptr != in ); + if ( nullptr == in ) { + return nullptr; + } return static_cast(in->mPrivate); } -} +} // Namespace Assimp -#endif +#endif // AI_SCENEPRIVATE_H_INCLUDED diff --git a/code/simd.cpp b/code/simd.cpp index 9c86cb970..bd951bffa 100644 --- a/code/simd.cpp +++ b/code/simd.cpp @@ -43,34 +43,36 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "simd.h" namespace Assimp { - bool CPUSupportsSSE2() { + +bool CPUSupportsSSE2() { #if defined(__x86_64__) || defined(_M_X64) - //* x86_64 always has SSE2 instructions */ - return true; + //* x86_64 always has SSE2 instructions */ + return true; #elif defined(__GNUC__) && defined(i386) - // for GCC x86 we check cpuid - unsigned int d; - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - : "=d" ( d ) - :"a" ( 1 ) ); - return ( d & 0x04000000 ) != 0; + // for GCC x86 we check cpuid + unsigned int d; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=d" ( d ) + :"a" ( 1 ) ); + return ( d & 0x04000000 ) != 0; #elif (defined(_MSC_VER) && defined(_M_IX86)) - // also check cpuid for MSVC x86 - unsigned int d; - __asm { - xor eax, eax - inc eax - push ebx - cpuid - pop ebx - mov d, edx - } - return ( d & 0x04000000 ) != 0; -#else - return false; -#endif + // also check cpuid for MSVC x86 + unsigned int d; + __asm { + xor eax, eax + inc eax + push ebx + cpuid + pop ebx + mov d, edx } + return ( d & 0x04000000 ) != 0; +#else + return false; +#endif } + +} // Namespace Assimp diff --git a/code/simd.h b/code/simd.h index 8fe2bb851..19117569d 100644 --- a/code/simd.h +++ b/code/simd.h @@ -46,6 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { +/// @brief Checks if the platform supports SSE2 optimization +/// @return true, if SSE2 is supported. false if SSE2 is not supported. bool ASSIMP_API CPUSupportsSSE2(); } // Namespace Assimp diff --git a/test/unit/AbstractImportExportBase.cpp b/test/unit/AbstractImportExportBase.cpp index f75ba4ea2..c09ec0fd7 100644 --- a/test/unit/AbstractImportExportBase.cpp +++ b/test/unit/AbstractImportExportBase.cpp @@ -45,5 +45,5 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace ::Assimp; AbstractImportExportBase::~AbstractImportExportBase() { - // empty + // empty } From 3bd80a2537b6cfeecec7852b578ede1234e5eb38 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 6 Apr 2018 12:05:30 +0200 Subject: [PATCH 29/30] closes https://github.com/assimp/assimp/issues/1881: make template-based get and put in streamreader/writer public. --- include/assimp/StreamReader.h | 2 +- include/assimp/StreamWriter.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/assimp/StreamReader.h b/include/assimp/StreamReader.h index 90cc65fee..3fab00ad2 100644 --- a/include/assimp/StreamReader.h +++ b/include/assimp/StreamReader.h @@ -283,7 +283,6 @@ public: return *this; } -private: // --------------------------------------------------------------------- /** Generic read method. ByteSwap::Swap(T*) *must* be defined */ template @@ -300,6 +299,7 @@ private: return f; } +private: // --------------------------------------------------------------------- void InternBegin() { if (!stream) { diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index 5ce3b172b..deb35fb4d 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -255,8 +255,6 @@ public: cursor = new_cursor; } -private: - // --------------------------------------------------------------------- /** Generic write method. ByteSwap::Swap(T*) *must* be defined */ template From 0a3fb04b041ba5723a74792959cdd06d6ee05ea5 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 6 Apr 2018 16:23:59 +0200 Subject: [PATCH 30/30] Update ScenePrivate.h add missing header --- code/ScenePrivate.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/ScenePrivate.h b/code/ScenePrivate.h index 6a44def2c..50959f455 100644 --- a/code/ScenePrivate.h +++ b/code/ScenePrivate.h @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SCENEPRIVATE_H_INCLUDED #define AI_SCENEPRIVATE_H_INCLUDED +#include #include namespace Assimp {