diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..18c914718 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Readme.md b/Readme.md index 917b8e8aa..9a8ac7c33 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,8 @@ Open Asset Import Library (assimp) ================================== -A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data. + +Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export. + ### Current project status ### [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg) @@ -14,7 +16,6 @@ A library to import and export various 3d-model-formats including scene-post-pro [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open") -[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. @@ -23,15 +24,19 @@ Additionally, assimp features various __mesh post processing tools__: normals an ### Latest Doc's ### Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). -### Get involved ### -This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). -
-You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs). -
-Please check our Wiki as well: https://github.com/assimp/assimp/wiki +### Prebuild binaries ### +Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib) If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb +### Communities ### +- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions) +- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/) +- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). +- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues) + +And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+ #### Supported file formats #### You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) @@ -66,28 +71,18 @@ Open Asset Import Library is implemented in C++. The directory structure looks l /port Ports to other languages and scripts to maintain those. /test Unit- and regression tests, test suite of models /tools Tools (old assimp viewer, command line `assimp`) - /samples A small number of samples to illustrate possible - use cases for Assimp + /samples A small number of samples to illustrate possible use-cases for Assimp The source code is organized in the following way: code/Common The base implementation for importers and the infrastructure + code/CApi Special implementations which are only used for the C-API + code/Geometry A collection of geometry tools + code/Material The material system + code/PBR An exporter for physical based models code/PostProcessing The post-processing steps code/AssetLib/ Implementation for import and export for the format -### Where to get help ### -To find our documentation, visit [our website](https://assimp.org/) or check out [Wiki](https://github.com/assimp/assimp/wiki) - -If the docs don't solve your problem, you can: -- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). -- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/) -- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions) -- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues) - -Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export. - -And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- ### Contributing ### Contributions to assimp are highly appreciated. The easiest way to get involved is to submit a pull request with your changes against the main repository's `master` branch. diff --git a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp index a65f9260e..d5160870a 100644 --- a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp +++ b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp @@ -815,6 +815,7 @@ nl_clean_loop: for (; next_it != nodeArray.end(); ++next_it) { if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) { // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop. + // FIXME: this leaks memory on test models test8.amf and test9.amf nodeArray.erase(nl_it); goto nl_clean_loop; diff --git a/code/AssetLib/Blender/BlenderScene.cpp b/code/AssetLib/Blender/BlenderScene.cpp index 3a9a02fd0..ac10d7302 100644 --- a/code/AssetLib/Blender/BlenderScene.cpp +++ b/code/AssetLib/Blender/BlenderScene.cpp @@ -569,7 +569,7 @@ void Structure ::Convert( const FileDatabase &db) const { ReadFieldArray(dest.co, "co", db); - ReadFieldArray(dest.no, "no", db); + ReadFieldArray(dest.no, "no", db); ReadField(dest.flag, "flag", db); //ReadField(dest.mat_nr,"mat_nr",db); ReadField(dest.bweight, "bweight", db); diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 37654746e..257845384 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -640,7 +640,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { const PropertyTable &props = model.Props(); - const auto zero_epsilon = ai_epsilon; + const auto zero_epsilon = Math::getEpsilon(); const aiVector3D all_ones(1.0f, 1.0f, 1.0f); for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { const TransformationComp comp = static_cast(i); @@ -1180,15 +1180,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c std::vector animMeshes; for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector &shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { + const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (const ShapeGeometry *shapeGeometry : shapeGeometries) { aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); - const std::vector &curVertices = shapeGeometry->GetVertices(); - const std::vector &curNormals = shapeGeometry->GetNormals(); - const std::vector &curIndices = shapeGeometry->GetIndices(); + const auto &curVertices = shapeGeometry->GetVertices(); + const auto &curNormals = shapeGeometry->GetNormals(); + const auto &curIndices = shapeGeometry->GetIndices(); //losing channel name if using shapeGeometry->Name() - animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name())); + // if blendShapeChannel Name is empty or don't have a ".", add geoMetryName; + auto aniName = FixAnimMeshName(blendShapeChannel->Name()); + auto geoMetryName = FixAnimMeshName(shapeGeometry->Name()); + if (aniName.empty()) { + aniName = geoMetryName; + } + else if (aniName.find('.') == aniName.npos) { + aniName += "." + geoMetryName; + } + animMesh->mName.Set(aniName); for (size_t j = 0; j < curIndices.size(); j++) { const unsigned int curIndex = curIndices.at(j); aiVector3D vertex = curVertices.at(j); @@ -1410,13 +1418,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co std::vector animMeshes; for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector &shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { + const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (const ShapeGeometry *shapeGeometry : shapeGeometries) { aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); - const std::vector &curVertices = shapeGeometry->GetVertices(); - const std::vector &curNormals = shapeGeometry->GetNormals(); - const std::vector &curIndices = shapeGeometry->GetIndices(); + const auto& curVertices = shapeGeometry->GetVertices(); + const auto& curNormals = shapeGeometry->GetNormals(); + const auto& curIndices = shapeGeometry->GetIndices(); animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); for (size_t j = 0; j < curIndices.size(); j++) { unsigned int curIndex = curIndices.at(j); diff --git a/code/AssetLib/FBX/FBXDeformer.cpp b/code/AssetLib/FBX/FBXDeformer.cpp index df134a401..1aab55ea9 100644 --- a/code/AssetLib/FBX/FBXDeformer.cpp +++ b/code/AssetLib/FBX/FBXDeformer.cpp @@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, for (const Connection* con : conns) { const BlendShapeChannel* const bspc = ProcessSimpleConnection(*con, false, "BlendShapeChannel -> BlendShape", element); if (bspc) { - blendShapeChannels.push_back(bspc); - continue; + auto pr = blendShapeChannels.insert(bspc); + if (!pr.second) { + FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID()); + } } } } @@ -179,8 +181,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const for (const Connection* con : conns) { const ShapeGeometry* const sg = ProcessSimpleConnection(*con, false, "Shape -> BlendShapeChannel", element); if (sg) { - shapeGeometries.push_back(sg); - continue; + auto pr = shapeGeometries.insert(sg); + if (!pr.second) { + FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID()); + } } } } diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index 8873d65fd..821d4d5cb 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define INCLUDED_AI_FBX_DOCUMENT_H #include +#include #include #include #include "FBXProperties.h" @@ -855,14 +856,14 @@ public: return fullWeights; } - const std::vector& GetShapeGeometries() const { + const std::unordered_set& GetShapeGeometries() const { return shapeGeometries; } private: float percent; WeightArray fullWeights; - std::vector shapeGeometries; + std::unordered_set shapeGeometries; }; /** DOM class for BlendShape deformers */ @@ -872,12 +873,12 @@ public: virtual ~BlendShape(); - const std::vector& BlendShapeChannels() const { + const std::unordered_set& BlendShapeChannels() const { return blendShapeChannels; } private: - std::vector blendShapeChannels; + std::unordered_set blendShapeChannels; }; /** DOM class for skin deformer clusters (aka sub-deformers) */ diff --git a/code/AssetLib/FBX/FBXMeshGeometry.cpp b/code/AssetLib/FBX/FBXMeshGeometry.cpp index ace4ad749..fcbaac169 100644 --- a/code/AssetLib/FBX/FBXMeshGeometry.cpp +++ b/code/AssetLib/FBX/FBXMeshGeometry.cpp @@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, } const BlendShape* const bsp = ProcessSimpleConnection(*con, false, "BlendShape -> Geometry", element); if (bsp) { - blendShapes.push_back(bsp); + auto pr = blendShapes.insert(bsp); + if (!pr.second) { + FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID()); + } } } } // ------------------------------------------------------------------------------------------------ -const std::vector& Geometry::GetBlendShapes() const { +const std::unordered_set& Geometry::GetBlendShapes() const { return blendShapes; } diff --git a/code/AssetLib/FBX/FBXMeshGeometry.h b/code/AssetLib/FBX/FBXMeshGeometry.h index f4a1a2673..3d67ec567 100644 --- a/code/AssetLib/FBX/FBXMeshGeometry.h +++ b/code/AssetLib/FBX/FBXMeshGeometry.h @@ -62,7 +62,7 @@ public: /// @param name The name instance /// @param doc The document instance Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); - + /// @brief The class destructor, default. virtual ~Geometry() = default; @@ -72,11 +72,12 @@ public: /// @brief Get the BlendShape attached to this geometry or nullptr /// @return The blendshape arrays. - const std::vector& GetBlendShapes() const; + const std::unordered_set& GetBlendShapes() const; private: const Skin* skin; - std::vector blendShapes; + std::unordered_set blendShapes; + }; typedef std::vector MatIndexArray; @@ -112,7 +113,7 @@ public: /// @return The binomal vector. const std::vector& GetBinormals() const; - /// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has. + /// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has. /// Vertices are taken from the vertex data arrays in sequential order. /// @return The face indices vector. const std::vector& GetFaceIndexCounts() const; diff --git a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp index 93d37536c..a8141fcc1 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp +++ b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp @@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() { temp_bones_.resize(header_->numbones); + // Create the main 'bones' node that will contain all MDL root bones. aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES); rootnode_children_.push_back(bones_node); - bones_node->mNumChildren = static_cast(header_->numbones); - bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; + + // Store roots bones IDs temporarily. + std::vector roots; // Create bone matrices in local space. for (int i = 0; i < header_->numbones; ++i) { - aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]); + aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]); aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]); temp_bones_[i].absolute_transform = bone_node->mTransformation = @@ -485,9 +487,11 @@ void HL1MDLLoader::read_bones() { aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2])); if (pbone[i].parent == -1) { - bone_node->mParent = scene_->mRootNode; + bone_node->mParent = bones_node; + roots.push_back(i); // This bone has no parent. Add it to the roots list. } else { - bone_node->mParent = bones_node->mChildren[pbone[i].parent]; + bone_node->mParent = temp_bones_[pbone[i].parent].node; + temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list. temp_bones_[i].absolute_transform = temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; @@ -496,6 +500,36 @@ void HL1MDLLoader::read_bones() { temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform; temp_bones_[i].offset_matrix.Inverse(); } + + // Allocate memory for each MDL root bone. + bones_node->mNumChildren = static_cast(roots.size()); + bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; + + // Build all bones children hierarchy starting from each MDL root bone. + for (size_t i = 0; i < roots.size(); ++i) + { + const TempBone &root_bone = temp_bones_[roots[i]]; + bones_node->mChildren[i] = root_bone.node; + build_bone_children_hierarchy(root_bone); + } +} + +void HL1MDLLoader::build_bone_children_hierarchy(const TempBone &bone) +{ + if (bone.children.empty()) + return; + + aiNode* bone_node = bone.node; + bone_node->mNumChildren = static_cast(bone.children.size()); + bone_node->mChildren = new aiNode *[bone_node->mNumChildren]; + + // Build each child bone's hierarchy recursively. + for (size_t i = 0; i < bone.children.size(); ++i) + { + const TempBone &child_bone = temp_bones_[bone.children[i]]; + bone_node->mChildren[i] = child_bone.node; + build_bone_children_hierarchy(child_bone); + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h index 0dba5099d..286b6e64c 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h +++ b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h @@ -143,6 +143,14 @@ private: */ static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); + /** + * \brief Build a bone's node children hierarchy. + * + * \param[in] bone The bone for which we must build all children hierarchy. + */ + struct TempBone; + void build_bone_children_hierarchy(const TempBone& bone); + /** Output scene to be filled */ aiScene *scene_; @@ -198,11 +206,13 @@ private: TempBone() : node(nullptr), absolute_transform(), - offset_matrix() {} + offset_matrix(), + children() {} aiNode *node; aiMatrix4x4 absolute_transform; aiMatrix4x4 offset_matrix; + std::vector children; // Bone children }; std::vector temp_bones_; diff --git a/code/CApi/AssimpCExport.cpp b/code/CApi/AssimpCExport.cpp index 5e43958d0..21e40205c 100644 --- a/code/CApi/AssimpCExport.cpp +++ b/code/CApi/AssimpCExport.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CApi/CInterfaceIOWrapper.cpp b/code/CApi/CInterfaceIOWrapper.cpp index 579545ecc..f0e46cd08 100644 --- a/code/CApi/CInterfaceIOWrapper.cpp +++ b/code/CApi/CInterfaceIOWrapper.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,14 +45,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { +// ------------------------------------------------------------------------------------------------ CIOStreamWrapper::~CIOStreamWrapper() { - /* Various places depend on this destructor to close the file */ - if (mFile) { + // Various places depend on this destructor to close the file + if (mFile != nullptr) { + mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); } } -// ................................................................... +// ------------------------------------------------------------------------------------------------ size_t CIOStreamWrapper::Read(void *pvBuffer, size_t pSize, size_t pCount) { @@ -62,7 +62,7 @@ size_t CIOStreamWrapper::Read(void *pvBuffer, return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount); } -// ................................................................... +// ------------------------------------------------------------------------------------------------ size_t CIOStreamWrapper::Write(const void *pvBuffer, size_t pSize, size_t pCount) { @@ -70,23 +70,23 @@ size_t CIOStreamWrapper::Write(const void *pvBuffer, return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount); } -// ................................................................... +// ------------------------------------------------------------------------------------------------ aiReturn CIOStreamWrapper::Seek(size_t pOffset, aiOrigin pOrigin) { return mFile->SeekProc(mFile, pOffset, pOrigin); } -// ................................................................... +// ------------------------------------------------------------------------------------------------ size_t CIOStreamWrapper::Tell() const { return mFile->TellProc(mFile); } -// ................................................................... +// ------------------------------------------------------------------------------------------------ size_t CIOStreamWrapper::FileSize() const { return mFile->FileSizeProc(mFile); } -// ................................................................... +// ------------------------------------------------------------------------------------------------ void CIOStreamWrapper::Flush() { return mFile->FlushProc(mFile); } diff --git a/code/CApi/CInterfaceIOWrapper.h b/code/CApi/CInterfaceIOWrapper.h index 768be3746..28d4c3e75 100644 --- a/code/CApi/CInterfaceIOWrapper.h +++ b/code/CApi/CInterfaceIOWrapper.h @@ -47,48 +47,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace Assimp { class CIOSystemWrapper; // ------------------------------------------------------------------------------------------------ -// Custom IOStream implementation for the C-API -class CIOStreamWrapper : public IOStream { +/// @brief Custom IOStream implementation for the C-API- +// ------------------------------------------------------------------------------------------------ +class CIOStreamWrapper final : public IOStream { public: - explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) : - mFile(pFile), - mIO(io) {} - ~CIOStreamWrapper(void); - - size_t Read(void *pvBuffer, size_t pSize, size_t pCount); - size_t Write(const void *pvBuffer, size_t pSize, size_t pCount); - aiReturn Seek(size_t pOffset, aiOrigin pOrigin); - size_t Tell(void) const; - size_t FileSize() const; - void Flush(); + explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io); + ~CIOStreamWrapper() override; + size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override; + size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override; + aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override; + size_t Tell(void) const override; + size_t FileSize() const override; + void Flush() override; private: aiFile *mFile; CIOSystemWrapper *mIO; }; -class CIOSystemWrapper : public IOSystem { +inline CIOStreamWrapper::CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) : + mFile(pFile), + mIO(io) { + ai_assert(io != nullptr); +} + +// ------------------------------------------------------------------------------------------------ +/// @brief Custom IO-System wrapper implementation for the C-API. +// ------------------------------------------------------------------------------------------------ +class CIOSystemWrapper final : public IOSystem { friend class CIOStreamWrapper; public: - explicit CIOSystemWrapper(aiFileIO *pFile) : - mFileSystem(pFile) {} - - bool Exists(const char *pFile) const; - char getOsSeparator() const; - IOStream *Open(const char *pFile, const char *pMode = "rb"); - void Close(IOStream *pFile); + explicit CIOSystemWrapper(aiFileIO *pFile); + ~CIOSystemWrapper() override = default; + bool Exists(const char *pFile) const override; + char getOsSeparator() const override; + IOStream *Open(const char *pFile, const char *pMode = "rb") override; + void Close(IOStream *pFile) override; private: aiFileIO *mFileSystem; }; +inline CIOSystemWrapper::CIOSystemWrapper(aiFileIO *pFile) : mFileSystem(pFile) { + ai_assert(pFile != nullptr); +} + } // namespace Assimp -#endif +#endif // AI_CIOSYSTEM_H_INCLUDED diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index a098f3e85..e05b4dd7b 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -218,6 +218,12 @@ SET( CApi_SRCS ) SOURCE_GROUP(CApi FILES ${CApi_SRCS}) +SET(Geometry_SRCS + Geometry/GeometryUtils.h + Geometry/GeometryUtils.cpp +) +SOURCE_GROUP(Geometry FILES ${Geometry_SRCS}) + SET( STEPParser_SRCS AssetLib/STEPParser/STEPFileReader.h AssetLib/STEPParser/STEPFileReader.cpp @@ -1129,6 +1135,7 @@ SET( assimp_src ${Core_SRCS} ${CApi_SRCS} ${Common_SRCS} + ${Geometry_SRCS} ${Logging_SRCS} ${Exporter_SRCS} ${PostProcessing_SRCS} @@ -1188,7 +1195,70 @@ TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp) IF (ASSIMP_WARNINGS_AS_ERRORS) MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)") IF (MSVC) - TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX) + + IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl + TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror + -Wno-unused-function + -Wno-microsoft-enum-value + -Wno-switch-enum + -Wno-covered-switch-default + -Wno-reserved-identifier + -Wno-c++98-compat-pedantic + -Wno-c++98-compat + -Wno-documentation + -Wno-documentation-unknown-command + -Wno-deprecated-dynamic-exception-spec + -Wno-undef + -Wno-suggest-destructor-override + -Wno-suggest-override + -Wno-inconsistent-missing-destructor-override + -Wno-zero-as-null-pointer-constant + -Wno-global-constructors + -Wno-exit-time-destructors + -Wno-extra-semi-stmt + -Wno-missing-prototypes + -Wno-old-style-cast + -Wno-cast-align + -Wno-cast-qual + -Wno-float-equal + -Wno-implicit-int-float-conversion + -Wno-sign-conversion + -Wno-implicit-float-conversion + -Wno-implicit-int-conversion + -Wno-float-conversion + -Wno-double-promotion + -Wno-unused-macros + -Wno-disabled-macro-expansion + -Wno-shadow-field + -Wno-shadow + -Wno-language-extension-token + -Wno-header-hygiene + -Wno-tautological-value-range-compare + -Wno-tautological-type-limit-compare + -Wno-missing-noreturn + -Wno-missing-variable-declarations + -Wno-extra-semi + -Wno-nonportable-system-include-path + -Wno-undefined-reinterpret-cast + -Wno-shift-sign-overflow + -Wno-deprecated-copy-with-user-provided-dtor + -Wno-deprecated-copy-with-dtor + -Wno-deprecated + -Wno-format-nonliteral + -Wno-format-non-iso + -Wno-comma + -Wno-unreachable-code-break + -Wno-unreachable-code-return + -Wno-unreachable-code + -Wno-implicit-fallthrough + -Wno-unused-template + -Wno-undefined-func-template + -Wno-nested-anon-types + -Wno-declaration-after-statement + ) + ELSE() + TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX) + ENDIF() ELSE() TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror) ENDIF() diff --git a/code/Common/PolyTools.h b/code/Common/PolyTools.h index 9837a2991..a5bd1090b 100644 --- a/code/Common/PolyTools.h +++ b/code/Common/PolyTools.h @@ -74,26 +74,8 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) { * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ template inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) { - // Point in triangle test using baryzentric coordinates - const aiVector2D v0 = p1 - p0; - const aiVector2D v1 = p2 - p0; - const aiVector2D v2 = pp - p0; - - double dot00 = v0 * v0; - double dot11 = v1 * v1; - const double dot01 = v0 * v1; - const double dot02 = v0 * v2; - const double dot12 = v1 * v2; - const double denom = dot00 * dot11 - dot01 * dot01; - if (denom == 0.0) { - return false; - } - - const double invDenom = 1.0 / denom; - dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom; - dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom; - - return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1); + // pp should be left side of the three triangle side, by ccw arrow + return OnLeftSideOfLine2D(p0, p1, pp) && OnLeftSideOfLine2D(p1, p2, pp) && OnLeftSideOfLine2D(p2, p0, pp); } diff --git a/code/Common/Subdivision.cpp b/code/Common/Subdivision.cpp index ac4078b47..3aea5d4c5 100644 --- a/code/Common/Subdivision.cpp +++ b/code/Common/Subdivision.cpp @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include using namespace Assimp; + void mydummy() {} #ifdef _MSC_VER diff --git a/code/Geometry/GeometryUtils.cpp b/code/Geometry/GeometryUtils.cpp new file mode 100644 index 000000000..ab735aa6e --- /dev/null +++ b/code/Geometry/GeometryUtils.cpp @@ -0,0 +1,79 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 "GeometryUtils.h" + +#include + +namespace Assimp { + +ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) { + ai_real s = (a + b + c) / 2; + ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 ); + return area; +} + +ai_real GeometryUtils::distance3D( const aiVector3D &vA, aiVector3D &vB ) { + const ai_real lx = ( vB.x - vA.x ); + const ai_real ly = ( vB.y - vA.y ); + const ai_real lz = ( vB.z - vA.z ); + ai_real a = lx*lx + ly*ly + lz*lz; + ai_real d = pow( a, (ai_real)0.5 ); + + return d; +} + +ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) { + ai_real area = 0; + + aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] ); + aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); + aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] ); + + ai_real a( distance3D( vA, vB ) ); + ai_real b( distance3D( vB, vC ) ); + ai_real c( distance3D( vC, vA ) ); + area = heron( a, b, c ); + + return area; +} + +} // namespace Assimp diff --git a/code/Geometry/GeometryUtils.h b/code/Geometry/GeometryUtils.h new file mode 100644 index 000000000..ab49380de --- /dev/null +++ b/code/Geometry/GeometryUtils.h @@ -0,0 +1,67 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 +#include + +namespace Assimp { + +// --------------------------------------------------------------------------- +/// @brief This helper class supports some basic geometry algorithms. +// --------------------------------------------------------------------------- +class GeometryUtils { +public: + static ai_real heron( ai_real a, ai_real b, ai_real c ); + + /// @brief Will compute the distance between 2 3D-vectors + /// @param vA Vector a. + /// @param vB Vector b. + /// @return The distance. + static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ); + + /// @brief Will calculate the area of a triangle described by a aiFace. + /// @param face The face + /// @param mesh The mesh containing the face + /// @return The area. + static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ); +}; + +} // namespace Assimp diff --git a/code/PostProcessing/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp index efc457766..a23ac856b 100644 --- a/code/PostProcessing/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -60,10 +60,6 @@ CalcTangentsProcess::CalcTangentsProcess() : // nothing to do here } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -CalcTangentsProcess::~CalcTangentsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool CalcTangentsProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/CalcTangentsProcess.h b/code/PostProcessing/CalcTangentsProcess.h index 018789bae..aaccb5307 100644 --- a/code/PostProcessing/CalcTangentsProcess.h +++ b/code/PostProcessing/CalcTangentsProcess.h @@ -59,14 +59,11 @@ namespace Assimp * because the joining of vertices also considers tangents and bitangents for * uniqueness. */ -class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess -{ +class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess { public: - CalcTangentsProcess(); - ~CalcTangentsProcess(); + ~CalcTangentsProcess() override = default; -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. @@ -74,24 +71,21 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - void SetupProperties(const Importer* pImp); - + void SetupProperties(const Importer* pImp) override; // setter for configMaxAngle - inline void SetMaxSmoothAngle(float f) - { + void SetMaxSmoothAngle(float f) { configMaxAngle =f; } protected: - // ------------------------------------------------------------------- /** Calculates tangents and bitangents for a specific mesh. * @param pMesh The mesh to process. @@ -103,10 +97,9 @@ protected: /** Executes the post processing step on the given imported data. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; private: - /** Configuration option: maximum smoothing angle, in radians*/ float configMaxAngle; unsigned int configSourceUV; diff --git a/code/PostProcessing/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp index 237409f02..a5472668b 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -57,14 +57,6 @@ namespace { const static ai_real angle_epsilon = ai_real( 0.95 ); } -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ComputeUVMappingProcess::ComputeUVMappingProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ComputeUVMappingProcess::~ComputeUVMappingProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const diff --git a/code/PostProcessing/ComputeUVMappingProcess.h b/code/PostProcessing/ComputeUVMappingProcess.h index 74744be7f..c4158f402 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.h +++ b/code/PostProcessing/ComputeUVMappingProcess.h @@ -59,13 +59,10 @@ namespace Assimp { /** ComputeUVMappingProcess - converts special mappings, such as spherical, * cylindrical or boxed to proper UV coordinates for rendering. */ -class ComputeUVMappingProcess : public BaseProcess -{ -public: - ComputeUVMappingProcess(); - ~ComputeUVMappingProcess(); - +class ComputeUVMappingProcess : public BaseProcess { public: + ComputeUVMappingProcess() = default; + ~ComputeUVMappingProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -73,14 +70,14 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; protected: @@ -125,8 +122,7 @@ protected: private: // temporary structure to describe a mapping - struct MappingInfo - { + struct MappingInfo { explicit MappingInfo(aiTextureMapping _type) : type (_type) , axis (0.f,1.f,0.f) @@ -137,8 +133,7 @@ private: aiVector3D axis; unsigned int uv; - bool operator== (const MappingInfo& other) - { + bool operator== (const MappingInfo& other) { return type == other.type && axis == other.axis; } }; diff --git a/code/PostProcessing/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp index 359c5a284..08e3fe48a 100644 --- a/code/PostProcessing/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -79,14 +79,6 @@ void flipUVs(aiMeshType *pMesh) { } // namespace -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -MakeLeftHandedProcess::MakeLeftHandedProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -MakeLeftHandedProcess::~MakeLeftHandedProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const { @@ -305,14 +297,6 @@ void FlipUVsProcess::ProcessMesh(aiMesh *pMesh) { #ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS // # FlipWindingOrderProcess -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FlipWindingOrderProcess::FlipWindingOrderProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FlipWindingOrderProcess::~FlipWindingOrderProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/ConvertToLHProcess.h b/code/PostProcessing/ConvertToLHProcess.h index 474056c3a..d0532277d 100644 --- a/code/PostProcessing/ConvertToLHProcess.h +++ b/code/PostProcessing/ConvertToLHProcess.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -72,22 +71,18 @@ namespace Assimp { * * @note RH-LH and LH-RH is the same, so this class can be used for both */ -class MakeLeftHandedProcess : public BaseProcess -{ - - +class MakeLeftHandedProcess : public BaseProcess { public: - MakeLeftHandedProcess(); - ~MakeLeftHandedProcess(); + MakeLeftHandedProcess() = default; + ~MakeLeftHandedProcess() override = default; // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; protected: - // ------------------------------------------------------------------- /** Recursively converts a node and all of its children */ @@ -120,24 +115,22 @@ protected: // --------------------------------------------------------------------------- /** Postprocessing step to flip the face order of the imported data */ -class FlipWindingOrderProcess : public BaseProcess -{ +class FlipWindingOrderProcess : public BaseProcess { friend class Importer; public: /** Constructor to be privately used by Importer */ - FlipWindingOrderProcess(); + FlipWindingOrderProcess() = default; /** Destructor, private as well */ - ~FlipWindingOrderProcess(); + ~FlipWindingOrderProcess() override = default; // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; -public: /** Some other types of post-processing require winding order flips */ static void ProcessMesh( aiMesh* pMesh); }; diff --git a/code/PostProcessing/DeboneProcess.cpp b/code/PostProcessing/DeboneProcess.cpp index 22a4397bf..2a8499dc5 100644 --- a/code/PostProcessing/DeboneProcess.cpp +++ b/code/PostProcessing/DeboneProcess.cpp @@ -43,42 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// @file DeboneProcess.cpp /** Implementation of the DeboneProcess post processing step */ - - // internal headers of the post-processing framework #include "ProcessHelper.h" #include "DeboneProcess.h" #include - using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -DeboneProcess::DeboneProcess() -{ - mNumBones = 0; - mNumBonesCanDoWithout = 0; - - mThreshold = AI_DEBONE_THRESHOLD; - mAllOrNone = false; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DeboneProcess::~DeboneProcess() = default; +DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool DeboneProcess::IsActive( unsigned int pFlags) const -{ +bool DeboneProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_Debone) != 0; } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void DeboneProcess::SetupProperties(const Importer* pImp) -{ +void DeboneProcess::SetupProperties(const Importer* pImp) { // get the current value of the property mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false; mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD); @@ -86,8 +70,7 @@ void DeboneProcess::SetupProperties(const Importer* pImp) // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void DeboneProcess::Execute( aiScene* pScene) -{ +void DeboneProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("DeboneProcess begin"); if(!pScene->mNumMeshes) { @@ -117,10 +100,8 @@ void DeboneProcess::Execute( aiScene* pScene) // build a new array of meshes for the scene std::vector meshes; - for(unsigned int a=0;amNumMeshes;a++) - { + for (unsigned int a=0;amNumMeshes; ++a) { aiMesh* srcMesh = pScene->mMeshes[a]; - std::vector > newMeshes; if(splitList[a]) { @@ -150,8 +131,7 @@ void DeboneProcess::Execute( aiScene* pScene) // and destroy the source mesh. It should be completely contained inside the new submeshes delete srcMesh; - } - else { + } else { // Mesh is kept unchanged - store it's new place in the mesh array mSubMeshIndices[a].emplace_back(static_cast(meshes.size()), (aiNode *)nullptr); meshes.push_back(srcMesh); @@ -173,8 +153,7 @@ void DeboneProcess::Execute( aiScene* pScene) // ------------------------------------------------------------------------------------------------ // Counts bones total/removable in a given mesh. -bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) -{ +bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) { if(!pMesh->HasBones()) { return false; } @@ -193,25 +172,23 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) for(unsigned int i=0;imNumBones;i++) { for(unsigned int j=0;jmBones[i]->mNumWeights;j++) { float w = pMesh->mBones[i]->mWeights[j].mWeight; - - if(w==0.0f) { + if (w == 0.0f) { continue; } unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; - if(w>=mThreshold) { - - if(vertexBones[vid]!=cUnowned) { - if(vertexBones[vid]==i) //double entry - { + if (w >= mThreshold) { + if (vertexBones[vid] != cUnowned) { + //double entry + if(vertexBones[vid]==i) { ASSIMP_LOG_WARN("Encountered double entry in bone weights"); - } - else //TODO: track attraction in order to break tie - { + } else { + //TODO: track attraction in order to break tie vertexBones[vid] = cCoowned; } - } - else vertexBones[vid] = i; + } else { + vertexBones[vid] = i; + } } if(!isBoneNecessary[i]) { @@ -227,13 +204,16 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) if(isInterstitialRequired) { for(unsigned int i=0;imNumFaces;i++) { unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; - - for(unsigned int j=1;jmFaces[i].mNumIndices;j++) { + for (unsigned int j=1;jmFaces[i].mNumIndices;j++) { unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; - if(v!=w) { - if(vmNumBones) isBoneNecessary[v] = true; - if(wmNumBones) isBoneNecessary[w] = true; + if (v != w) { + if(vmNumBones) { + isBoneNecessary[v] = true; + } + if (wmNumBones) { + isBoneNecessary[w] = true; + } } } } @@ -252,8 +232,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) // ------------------------------------------------------------------------------------------------ // Splits the given mesh by bone count. -void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const -{ +void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const { // same deal here as ConsiderMesh basically std::vector isBoneNecessary(pMesh->mNumBones,false); @@ -371,8 +350,7 @@ void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMe // ------------------------------------------------------------------------------------------------ // Recursively updates the node's mesh list to account for the changed mesh list -void DeboneProcess::UpdateNode(aiNode* pNode) const -{ +void DeboneProcess::UpdateNode(aiNode* pNode) const { // rebuild the node's mesh index list std::vector newMeshList; @@ -430,8 +408,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const // ------------------------------------------------------------------------------------------------ // Apply the node transformation to a mesh -void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const -{ +void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const { // Check whether we need to transform the coordinates at all if (!mat.IsIdentity()) { diff --git a/code/PostProcessing/DeboneProcess.h b/code/PostProcessing/DeboneProcess.h index cb072b7eb..ae4448e0e 100644 --- a/code/PostProcessing/DeboneProcess.h +++ b/code/PostProcessing/DeboneProcess.h @@ -70,7 +70,7 @@ namespace Assimp { class DeboneProcess : public BaseProcess { public: DeboneProcess(); - ~DeboneProcess(); + ~DeboneProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. @@ -79,14 +79,14 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; protected: // ------------------------------------------------------------------- @@ -94,7 +94,7 @@ protected: * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- /** Counts bones total/removable in a given mesh. diff --git a/code/PostProcessing/DropFaceNormalsProcess.cpp b/code/PostProcessing/DropFaceNormalsProcess.cpp index f85daa588..223482374 100644 --- a/code/PostProcessing/DropFaceNormalsProcess.cpp +++ b/code/PostProcessing/DropFaceNormalsProcess.cpp @@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -DropFaceNormalsProcess::DropFaceNormalsProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DropFaceNormalsProcess::~DropFaceNormalsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { diff --git a/code/PostProcessing/DropFaceNormalsProcess.h b/code/PostProcessing/DropFaceNormalsProcess.h index 50abdc727..df542f2ba 100644 --- a/code/PostProcessing/DropFaceNormalsProcess.h +++ b/code/PostProcessing/DropFaceNormalsProcess.h @@ -55,8 +55,8 @@ namespace Assimp { */ class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { public: - DropFaceNormalsProcess(); - ~DropFaceNormalsProcess(); + DropFaceNormalsProcess() = default; + ~DropFaceNormalsProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -64,15 +64,14 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); - + void Execute( aiScene* pScene) override; private: bool DropMeshFaceNormals(aiMesh* pcMesh); diff --git a/code/PostProcessing/EmbedTexturesProcess.cpp b/code/PostProcessing/EmbedTexturesProcess.cpp index dc7e54ac1..d5d2ef872 100644 --- a/code/PostProcessing/EmbedTexturesProcess.cpp +++ b/code/PostProcessing/EmbedTexturesProcess.cpp @@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -EmbedTexturesProcess::EmbedTexturesProcess() = default; - -EmbedTexturesProcess::~EmbedTexturesProcess() = default; - bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { return (pFlags & aiProcess_EmbedTextures) != 0; } diff --git a/code/PostProcessing/EmbedTexturesProcess.h b/code/PostProcessing/EmbedTexturesProcess.h index c3e63612c..77d4d9c72 100644 --- a/code/PostProcessing/EmbedTexturesProcess.h +++ b/code/PostProcessing/EmbedTexturesProcess.h @@ -62,19 +62,19 @@ namespace Assimp { class ASSIMP_API EmbedTexturesProcess : public BaseProcess { public: /// The default class constructor. - EmbedTexturesProcess(); + EmbedTexturesProcess() = default; /// The class destructor. - virtual ~EmbedTexturesProcess(); + ~EmbedTexturesProcess() override = default; /// Overwritten, @see BaseProcess - virtual bool IsActive(unsigned int pFlags) const; + bool IsActive(unsigned int pFlags) const override; /// Overwritten, @see BaseProcess - virtual void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; /// Overwritten, @see BaseProcess - virtual void Execute(aiScene* pScene); + virtual void Execute(aiScene* pScene) override; private: // Resolve the path and add the file content to the scene as a texture. diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp index 344979949..5874c17d2 100644 --- a/code/PostProcessing/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ProcessHelper.h" #include "FindDegenerates.h" +#include "Geometry/GeometryUtils.h" #include @@ -63,10 +64,6 @@ FindDegeneratesProcess::FindDegeneratesProcess() : // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindDegeneratesProcess::~FindDegeneratesProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { @@ -132,37 +129,6 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_mapmVertices[ face.mIndices[ 0 ] ] ); - aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); - aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] ); - - ai_real a( distance3D( vA, vB ) ); - ai_real b( distance3D( vB, vC ) ); - ai_real c( distance3D( vC, vA ) ); - area = heron( a, b, c ); - - return area; -} - // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported mesh bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { @@ -218,7 +184,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { if ( mConfigCheckAreaOfTriangle ) { if ( face.mNumIndices == 3 ) { - ai_real area = calculateAreaOfTriangle( face, mesh ); + ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh ); if (area < ai_epsilon) { if ( mConfigRemoveDegenerates ) { remove_me[ a ] = true; diff --git a/code/PostProcessing/FindDegenerates.h b/code/PostProcessing/FindDegenerates.h index 6fe1e929b..6b37a47cf 100644 --- a/code/PostProcessing/FindDegenerates.h +++ b/code/PostProcessing/FindDegenerates.h @@ -59,19 +59,19 @@ namespace Assimp { class ASSIMP_API FindDegeneratesProcess : public BaseProcess { public: FindDegeneratesProcess(); - ~FindDegeneratesProcess(); + ~FindDegeneratesProcess() override = default; // ------------------------------------------------------------------- // Check whether step is active - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- // Execute step on a given scene - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- // Setup import settings - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- // Execute step on a given mesh @@ -105,23 +105,19 @@ private: bool mConfigCheckAreaOfTriangle; }; -inline -void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) { +inline void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) { mConfigRemoveDegenerates = enabled; } -inline -bool FindDegeneratesProcess::IsInstantRemoval() const { +inline bool FindDegeneratesProcess::IsInstantRemoval() const { return mConfigRemoveDegenerates; } -inline -void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) { +inline void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) { mConfigCheckAreaOfTriangle = enabled; } -inline -bool FindDegeneratesProcess::isAreaCheckEnabled() const { +inline bool FindDegeneratesProcess::isAreaCheckEnabled() const { return mConfigCheckAreaOfTriangle; } diff --git a/code/PostProcessing/FindInstancesProcess.cpp b/code/PostProcessing/FindInstancesProcess.cpp index 07a0f66db..55974b1c3 100644 --- a/code/PostProcessing/FindInstancesProcess.cpp +++ b/code/PostProcessing/FindInstancesProcess.cpp @@ -58,10 +58,6 @@ FindInstancesProcess::FindInstancesProcess() : configSpeedFlag (false) {} -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInstancesProcess::~FindInstancesProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool FindInstancesProcess::IsActive( unsigned int pFlags) const diff --git a/code/PostProcessing/FindInstancesProcess.h b/code/PostProcessing/FindInstancesProcess.h index b501d88d5..6927301ca 100644 --- a/code/PostProcessing/FindInstancesProcess.h +++ b/code/PostProcessing/FindInstancesProcess.h @@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "PostProcessing/ProcessHelper.h" class FindInstancesProcessTest; -namespace Assimp { + +namespace Assimp { // ------------------------------------------------------------------------------- /** @brief Get a pseudo(!)-hash representing a mesh. @@ -60,8 +61,7 @@ namespace Assimp { * @param in Input mesh * @return Hash. */ -inline -uint64_t GetMeshHash(aiMesh* in) { +inline uint64_t GetMeshHash(aiMesh* in) { ai_assert(nullptr != in); // ... get an unique value representing the vertex format of the mesh @@ -83,8 +83,7 @@ uint64_t GetMeshHash(aiMesh* in) { * @param e Epsilon * @return true if the arrays are identical */ -inline -bool CompareArrays(const aiVector3D* first, const aiVector3D* second, +inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second, unsigned int size, float e) { for (const aiVector3D* end = first+size; first != end; ++first,++second) { if ( (*first - *second).SquareLength() >= e) @@ -107,31 +106,27 @@ inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second, // --------------------------------------------------------------------------- /** @brief A post-processing steps to search for instanced meshes */ -class FindInstancesProcess : public BaseProcess -{ +class FindInstancesProcess : public BaseProcess { public: - FindInstancesProcess(); - ~FindInstancesProcess(); + ~FindInstancesProcess() override = default; -public: // ------------------------------------------------------------------- // Check whether step is active in given flags combination - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- // Execute step on a given scene - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- // Setup properties prior to executing the process - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; private: - bool configSpeedFlag; - }; // ! end class FindInstancesProcess + } // ! end namespace Assimp #endif // !! AI_FINDINSTANCES_H_INC diff --git a/code/PostProcessing/FindInvalidDataProcess.cpp b/code/PostProcessing/FindInvalidDataProcess.cpp index c65208cbd..bb8e365a1 100644 --- a/code/PostProcessing/FindInvalidDataProcess.cpp +++ b/code/PostProcessing/FindInvalidDataProcess.cpp @@ -60,10 +60,6 @@ FindInvalidDataProcess::FindInvalidDataProcess() : // nothing to do here } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInvalidDataProcess::~FindInvalidDataProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/FindInvalidDataProcess.h b/code/PostProcessing/FindInvalidDataProcess.h index 5ea895c59..024eb9b1e 100644 --- a/code/PostProcessing/FindInvalidDataProcess.h +++ b/code/PostProcessing/FindInvalidDataProcess.h @@ -64,35 +64,37 @@ namespace Assimp { * which have zero normal vectors. */ class ASSIMP_API FindInvalidDataProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. FindInvalidDataProcess(); - ~FindInvalidDataProcess(); + ~FindInvalidDataProcess() override = default; // ------------------------------------------------------------------- - // - bool IsActive(unsigned int pFlags) const; + /// Returns active state. + bool IsActive(unsigned int pFlags) const override; // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer *pImp); + /// Setup import settings + void SetupProperties(const Importer *pImp) override; // ------------------------------------------------------------------- - // Run the step - void Execute(aiScene *pScene); + /// Run the step + void Execute(aiScene *pScene) override; // ------------------------------------------------------------------- - /** Executes the post-processing step on the given mesh - * @param pMesh The mesh to process. - * @return 0 - nothing, 1 - removed sth, 2 - please delete me */ + /// Executes the post-processing step on the given mesh + /// @param pMesh The mesh to process. + /// @return 0 - nothing, 1 - removed sth, 2 - please delete me */ int ProcessMesh(aiMesh *pMesh); // ------------------------------------------------------------------- - /** Executes the post-processing step on the given animation - * @param anim The animation to process. */ + /// Executes the post-processing step on the given animation + /// @param anim The animation to process. */ void ProcessAnimation(aiAnimation *anim); // ------------------------------------------------------------------- - /** Executes the post-processing step on the given anim channel - * @param anim The animation channel to process.*/ + /// Executes the post-processing step on the given anim channel + /// @param anim The animation channel to process.*/ void ProcessAnimationChannel(aiNodeAnim *anim); private: diff --git a/code/PostProcessing/FixNormalsStep.cpp b/code/PostProcessing/FixNormalsStep.cpp index 3791bd35a..54ac05cc8 100644 --- a/code/PostProcessing/FixNormalsStep.cpp +++ b/code/PostProcessing/FixNormalsStep.cpp @@ -56,26 +56,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FixInfacingNormalsProcess::FixInfacingNormalsProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FixInfacingNormalsProcess::~FixInfacingNormalsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const -{ +bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_FixInfacingNormals) != 0; } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void FixInfacingNormalsProcess::Execute( aiScene* pScene) -{ +void FixInfacingNormalsProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin"); bool bHas( false ); diff --git a/code/PostProcessing/FixNormalsStep.h b/code/PostProcessing/FixNormalsStep.h index b7d3ba386..20be1958b 100644 --- a/code/PostProcessing/FixNormalsStep.h +++ b/code/PostProcessing/FixNormalsStep.h @@ -49,8 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- /** The FixInfacingNormalsProcess tries to determine whether the normal @@ -59,8 +58,10 @@ namespace Assimp */ class FixInfacingNormalsProcess : public BaseProcess { public: - FixInfacingNormalsProcess(); - ~FixInfacingNormalsProcess(); + // ------------------------------------------------------------------- + /// The default class constructor / destructor. + FixInfacingNormalsProcess() = default; + ~FixInfacingNormalsProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -68,14 +69,14 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; protected: diff --git a/code/PostProcessing/GenBoundingBoxesProcess.cpp b/code/PostProcessing/GenBoundingBoxesProcess.cpp index 52a0861e5..ca8e4d6d0 100644 --- a/code/PostProcessing/GenBoundingBoxesProcess.cpp +++ b/code/PostProcessing/GenBoundingBoxesProcess.cpp @@ -48,10 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -GenBoundingBoxesProcess::GenBoundingBoxesProcess() = default; - -GenBoundingBoxesProcess::~GenBoundingBoxesProcess() = default; - bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const { return 0 != ( pFlags & aiProcess_GenBoundingBoxes ); } diff --git a/code/PostProcessing/GenBoundingBoxesProcess.h b/code/PostProcessing/GenBoundingBoxesProcess.h index 0b7591b6d..0cf8514f4 100644 --- a/code/PostProcessing/GenBoundingBoxesProcess.h +++ b/code/PostProcessing/GenBoundingBoxesProcess.h @@ -19,7 +19,7 @@ conditions are met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - +s * 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 @@ -54,18 +54,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -/** Post-processing process to find axis-aligned bounding volumes for amm meshes - * used in a scene +/** + * @brief Post-processing process to find axis-aligned bounding volumes for amm meshes + * used in a scene. */ class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess { public: - /// The class constructor. - GenBoundingBoxesProcess(); - /// The class destructor. - ~GenBoundingBoxesProcess(); - /// Will return true, if aiProcess_GenBoundingBoxes is defined. + // ------------------------------------------------------------------- + /// The default class constructor / destructor. + GenBoundingBoxesProcess() = default; + ~GenBoundingBoxesProcess() override = default; + + // ------------------------------------------------------------------- + /// @brief Will return true, if aiProcess_GenBoundingBoxes is defined. bool IsActive(unsigned int pFlags) const override; - /// The execution callback. + + // ------------------------------------------------------------------- + /// @brief The execution callback. void Execute(aiScene* pScene) override; }; diff --git a/code/PostProcessing/GenFaceNormalsProcess.cpp b/code/PostProcessing/GenFaceNormalsProcess.cpp index d3520d4b2..1d259ce22 100644 --- a/code/PostProcessing/GenFaceNormalsProcess.cpp +++ b/code/PostProcessing/GenFaceNormalsProcess.cpp @@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -GenFaceNormalsProcess::GenFaceNormalsProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenFaceNormalsProcess::~GenFaceNormalsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/GenFaceNormalsProcess.h b/code/PostProcessing/GenFaceNormalsProcess.h index c2f157e20..94794631e 100644 --- a/code/PostProcessing/GenFaceNormalsProcess.h +++ b/code/PostProcessing/GenFaceNormalsProcess.h @@ -47,35 +47,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Common/BaseProcess.h" #include -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes face normals for all faces of all meshes -*/ -class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess -{ +/** + * @brief The GenFaceNormalsProcess computes face normals for all faces of all meshes + */ +class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. + GenFaceNormalsProcess() = default; + ~GenFaceNormalsProcess() override = default; - GenFaceNormalsProcess(); - ~GenFaceNormalsProcess(); - -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); - + void Execute( aiScene* pScene) override; private: bool GenMeshFaceNormals(aiMesh* pcMesh); diff --git a/code/PostProcessing/GenVertexNormalsProcess.cpp b/code/PostProcessing/GenVertexNormalsProcess.cpp index 5b9033383..c8afac297 100644 --- a/code/PostProcessing/GenVertexNormalsProcess.cpp +++ b/code/PostProcessing/GenVertexNormalsProcess.cpp @@ -60,10 +60,6 @@ GenVertexNormalsProcess::GenVertexNormalsProcess() : // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenVertexNormalsProcess::~GenVertexNormalsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const { @@ -109,10 +105,10 @@ void GenVertexNormalsProcess::Execute(aiScene *pScene) { // Executes the post processing step on the given imported data. bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) { if (nullptr != pMesh->mNormals) { - if (force_) - delete[] pMesh->mNormals; - else + if (!force_) { return false; + } + delete[] pMesh->mNormals; } // If the mesh consists of lines and/or points but not of @@ -144,8 +140,9 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int m const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]]; // Boolean XOR - if either but not both of these flags is set, then the winding order has // changed and the cross product to calculate the normal needs to be reversed - if (flippedWindingOrder_ != leftHanded_) + if (flippedWindingOrder_ != leftHanded_) { std::swap(pV2, pV3); + } const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); for (unsigned int i = 0; i < face.mNumIndices; ++i) { diff --git a/code/PostProcessing/GenVertexNormalsProcess.h b/code/PostProcessing/GenVertexNormalsProcess.h index 370bf42b1..b7db9c4f2 100644 --- a/code/PostProcessing/GenVertexNormalsProcess.h +++ b/code/PostProcessing/GenVertexNormalsProcess.h @@ -60,8 +60,10 @@ namespace Assimp { */ class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. GenVertexNormalsProcess(); - ~GenVertexNormalsProcess(); + ~GenVertexNormalsProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. @@ -70,22 +72,21 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); - + void Execute( aiScene* pScene) override; // setter for configMaxAngle inline void SetMaxSmoothAngle(ai_real f) { diff --git a/code/PostProcessing/ImproveCacheLocality.cpp b/code/PostProcessing/ImproveCacheLocality.cpp index 197856171..9336d6b17 100644 --- a/code/PostProcessing/ImproveCacheLocality.cpp +++ b/code/PostProcessing/ImproveCacheLocality.cpp @@ -68,10 +68,6 @@ ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const { diff --git a/code/PostProcessing/ImproveCacheLocality.h b/code/PostProcessing/ImproveCacheLocality.h index b2074a17c..6f4d55719 100644 --- a/code/PostProcessing/ImproveCacheLocality.h +++ b/code/PostProcessing/ImproveCacheLocality.h @@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- /** The ImproveCacheLocalityProcess reorders all faces for improved vertex @@ -61,26 +60,24 @@ namespace Assimp * * @note This step expects triagulated input data. */ -class ImproveCacheLocalityProcess : public BaseProcess -{ +class ImproveCacheLocalityProcess : public BaseProcess { public: - + // ------------------------------------------------------------------- + /// The default class constructor / destructor. ImproveCacheLocalityProcess(); - ~ImproveCacheLocalityProcess(); - -public: + ~ImproveCacheLocalityProcess() override = default; // ------------------------------------------------------------------- // Check whether the pp step is active - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- // Executes the pp step on a given scene - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- // Configures the pp step - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; protected: // ------------------------------------------------------------------- diff --git a/code/PostProcessing/JoinVerticesProcess.h b/code/PostProcessing/JoinVerticesProcess.h index b05d74ef5..aa8dc5794 100644 --- a/code/PostProcessing/JoinVerticesProcess.h +++ b/code/PostProcessing/JoinVerticesProcess.h @@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- /** The JoinVerticesProcess unites identical vertices in all imported meshes. @@ -65,12 +64,9 @@ namespace Assimp class ASSIMP_API JoinVerticesProcess : public BaseProcess { public: // ------------------------------------------------------------------- - /// @brief The default class constructor. - JoinVerticesProcess() = default; - - // ------------------------------------------------------------------- - /// @brief The default class destructor. - ~JoinVerticesProcess() = default; + /// The default class constructor / destructor. + JoinVerticesProcess() = default; + ~JoinVerticesProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -78,14 +74,14 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- /** Unites identical vertices in the given mesh. diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 51fb43dfc..7047ec0f1 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -53,11 +53,9 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -LimitBoneWeightsProcess::~LimitBoneWeightsProcess() = default; +LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. diff --git a/code/PostProcessing/LimitBoneWeightsProcess.h b/code/PostProcessing/LimitBoneWeightsProcess.h index 22d286b68..b19d536cf 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.h +++ b/code/PostProcessing/LimitBoneWeightsProcess.h @@ -74,8 +74,10 @@ namespace Assimp { */ class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. LimitBoneWeightsProcess(); - ~LimitBoneWeightsProcess(); + ~LimitBoneWeightsProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. @@ -84,27 +86,27 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Limits the bone weight count for all vertices in the given mesh. - * @param pMesh The mesh to process. - */ - void ProcessMesh( aiMesh* pMesh); + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; + + // ------------------------------------------------------------------- + /** Limits the bone weight count for all vertices in the given mesh. + * @param pMesh The mesh to process. + */ + void ProcessMesh( aiMesh* pMesh); // ------------------------------------------------------------------- /** Describes a bone weight on a vertex */ diff --git a/code/PostProcessing/MakeVerboseFormat.cpp b/code/PostProcessing/MakeVerboseFormat.cpp index 0f5276cf3..1cc2fdc02 100644 --- a/code/PostProcessing/MakeVerboseFormat.cpp +++ b/code/PostProcessing/MakeVerboseFormat.cpp @@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::MakeVerboseFormatProcess() = default; -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::~MakeVerboseFormatProcess() = default; // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void MakeVerboseFormatProcess::Execute(aiScene *pScene) { diff --git a/code/PostProcessing/MakeVerboseFormat.h b/code/PostProcessing/MakeVerboseFormat.h index 6b81da622..f21f5919e 100644 --- a/code/PostProcessing/MakeVerboseFormat.h +++ b/code/PostProcessing/MakeVerboseFormat.h @@ -66,22 +66,19 @@ namespace Assimp { * The step has been added because it was required by the viewer, however * it has been moved to the main library since others might find it * useful, too. */ -class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess -{ -public: - - - MakeVerboseFormatProcess(); - ~MakeVerboseFormatProcess(); - +class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. + MakeVerboseFormatProcess() = default; + ~MakeVerboseFormatProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not */ - bool IsActive( unsigned int /*pFlags*/ ) const + bool IsActive( unsigned int /*pFlags*/ ) const override { // NOTE: There is no direct flag that corresponds to // this postprocess step. @@ -92,7 +89,7 @@ public: /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; public: diff --git a/code/PostProcessing/OptimizeGraph.cpp b/code/PostProcessing/OptimizeGraph.cpp index 26b06e9b6..bcd654634 100644 --- a/code/PostProcessing/OptimizeGraph.cpp +++ b/code/PostProcessing/OptimizeGraph.cpp @@ -78,10 +78,6 @@ OptimizeGraphProcess::OptimizeGraphProcess() : // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeGraphProcess::~OptimizeGraphProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/OptimizeGraph.h b/code/PostProcessing/OptimizeGraph.h index f5caa139c..23e59e67d 100644 --- a/code/PostProcessing/OptimizeGraph.h +++ b/code/PostProcessing/OptimizeGraph.h @@ -71,8 +71,10 @@ namespace Assimp { */ class OptimizeGraphProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. OptimizeGraphProcess(); - ~OptimizeGraphProcess(); + ~OptimizeGraphProcess() override = default; // ------------------------------------------------------------------- bool IsActive( unsigned int pFlags) const override; diff --git a/code/PostProcessing/OptimizeMeshes.cpp b/code/PostProcessing/OptimizeMeshes.cpp index a8c01e2d7..0fd597808 100644 --- a/code/PostProcessing/OptimizeMeshes.cpp +++ b/code/PostProcessing/OptimizeMeshes.cpp @@ -69,10 +69,6 @@ OptimizeMeshesProcess::OptimizeMeshesProcess() // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeMeshesProcess::~OptimizeMeshesProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const diff --git a/code/PostProcessing/OptimizeMeshes.h b/code/PostProcessing/OptimizeMeshes.h index b80f98d5d..0b062959a 100644 --- a/code/PostProcessing/OptimizeMeshes.h +++ b/code/PostProcessing/OptimizeMeshes.h @@ -68,11 +68,10 @@ namespace Assimp { */ class OptimizeMeshesProcess : public BaseProcess { public: - /// @brief The class constructor. + // ------------------------------------------------------------------- + /// The default class constructor / destructor. OptimizeMeshesProcess(); - - /// @brief The class destructor. - ~OptimizeMeshesProcess(); + ~OptimizeMeshesProcess() override = default; /** @brief Internal utility to store additional mesh info */ @@ -94,16 +93,14 @@ public: unsigned int output_id; }; -public: // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** @brief Specify whether you want meshes with different diff --git a/code/PostProcessing/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp index 9ac90d277..b6bb6155e 100644 --- a/code/PostProcessing/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -68,10 +68,6 @@ PretransformVertices::PretransformVertices() : // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -PretransformVertices::~PretransformVertices() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool PretransformVertices::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/PretransformVertices.h b/code/PostProcessing/PretransformVertices.h index 14e5139ec..7c2b5e99e 100644 --- a/code/PostProcessing/PretransformVertices.h +++ b/code/PostProcessing/PretransformVertices.h @@ -68,8 +68,10 @@ namespace Assimp { */ class ASSIMP_API PretransformVertices : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. PretransformVertices(); - ~PretransformVertices(); + ~PretransformVertices() override = default; // ------------------------------------------------------------------- // Check whether step is active diff --git a/code/PostProcessing/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp index 3c3cd59e0..dbc3c8822 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -62,10 +62,6 @@ RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() // nothing to do here } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const diff --git a/code/PostProcessing/RemoveRedundantMaterials.h b/code/PostProcessing/RemoveRedundantMaterials.h index e8c1478fd..1b42bea55 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.h +++ b/code/PostProcessing/RemoveRedundantMaterials.h @@ -59,23 +59,22 @@ namespace Assimp { */ class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { public: - /// The default class constructor. + // ------------------------------------------------------------------- + /// The default class constructor / destructor. RemoveRedundantMatsProcess(); - - /// The class destructor. - ~RemoveRedundantMatsProcess(); + ~RemoveRedundantMatsProcess() override = default; // ------------------------------------------------------------------- // Check whether step is active - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- // Execute step on a given scene - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- // Setup import settings - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** @brief Set list of fixed (inmutable) materials diff --git a/code/PostProcessing/RemoveVCProcess.cpp b/code/PostProcessing/RemoveVCProcess.cpp index 8bbe791f6..35047dc0a 100644 --- a/code/PostProcessing/RemoveVCProcess.cpp +++ b/code/PostProcessing/RemoveVCProcess.cpp @@ -56,10 +56,6 @@ using namespace Assimp; RemoveVCProcess::RemoveVCProcess() : configDeleteFlags(), mScene() {} -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveVCProcess::~RemoveVCProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool RemoveVCProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/RemoveVCProcess.h b/code/PostProcessing/RemoveVCProcess.h index cf1086882..45c0b3a71 100644 --- a/code/PostProcessing/RemoveVCProcess.h +++ b/code/PostProcessing/RemoveVCProcess.h @@ -58,11 +58,10 @@ namespace Assimp { */ class ASSIMP_API RemoveVCProcess : public BaseProcess { public: - /// The default class constructor. + // ------------------------------------------------------------------- + /// The default class constructor / destructor. RemoveVCProcess(); - - /// The class destructor. - ~RemoveVCProcess(); + ~RemoveVCProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -70,37 +69,35 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); + virtual void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** Manually setup the configuration flags for the step * * @param Bitwise combination of the #aiComponent enumerated values. */ - void SetDeleteFlags(unsigned int f) - { + void SetDeleteFlags(unsigned int f) { configDeleteFlags = f; } // ------------------------------------------------------------------- /** Query the current configuration. */ - unsigned int GetDeleteFlags() const - { + unsigned int GetDeleteFlags() const { return configDeleteFlags; } diff --git a/code/PostProcessing/ScaleProcess.cpp b/code/PostProcessing/ScaleProcess.cpp index 34f68539a..665f28a7e 100644 --- a/code/PostProcessing/ScaleProcess.cpp +++ b/code/PostProcessing/ScaleProcess.cpp @@ -47,25 +47,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -ScaleProcess::ScaleProcess() -: BaseProcess() -, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { +// ------------------------------------------------------------------------------------------------ +ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { + // empty } -ScaleProcess::~ScaleProcess() = default; - +// ------------------------------------------------------------------------------------------------ void ScaleProcess::setScale( ai_real scale ) { mScale = scale; } +// ------------------------------------------------------------------------------------------------ ai_real ScaleProcess::getScale() const { return mScale; } +// ------------------------------------------------------------------------------------------------ bool ScaleProcess::IsActive( unsigned int pFlags ) const { return ( pFlags & aiProcess_GlobalScale ) != 0; } +// ------------------------------------------------------------------------------------------------ void ScaleProcess::SetupProperties( const Importer* pImp ) { // User scaling mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); @@ -78,6 +80,7 @@ void ScaleProcess::SetupProperties( const Importer* pImp ) { mScale *= importerScale; } +// ------------------------------------------------------------------------------------------------ void ScaleProcess::Execute( aiScene* pScene ) { if(mScale == 1.0f) { return; // nothing to scale @@ -96,37 +99,30 @@ void ScaleProcess::Execute( aiScene* pScene ) { } // Process animations and update position transform to new unit system - for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) - { + for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) { aiAnimation* animation = pScene->mAnimations[animationID]; - for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) - { + for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) { aiNodeAnim* anim = animation->mChannels[animationChannel]; - for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) - { + for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) { aiVectorKey& vectorKey = anim->mPositionKeys[posKey]; vectorKey.mValue *= mScale; } } } - for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) - { + for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) { aiMesh *mesh = pScene->mMeshes[meshID]; // Reconstruct mesh vertices to the new unit system - for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) - { + for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) { aiVector3D& vertex = mesh->mVertices[vertexID]; vertex *= mScale; } - // bone placement / scaling - for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) - { + for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) { // Reconstruct matrix by transform rather than by scale // This prevent scale values being changed which can // be meaningful in some cases @@ -152,12 +148,10 @@ void ScaleProcess::Execute( aiScene* pScene ) { // animation mesh processing // convert by position rather than scale. - for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) - { + for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) { aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID]; - for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) - { + for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) { aiVector3D& vertex = animMesh->mVertices[vertexID]; vertex *= mScale; } @@ -167,16 +161,17 @@ void ScaleProcess::Execute( aiScene* pScene ) { traverseNodes( pScene->mRootNode ); } +// ------------------------------------------------------------------------------------------------ void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { applyScaling( node ); - for( size_t i = 0; i < node->mNumChildren; i++) - { + for( size_t i = 0; i < node->mNumChildren; i++) { // recurse into the tree until we are done! traverseNodes( node->mChildren[i], nested_node_id+1 ); } } +// ------------------------------------------------------------------------------------------------ void ScaleProcess::applyScaling( aiNode *currentNode ) { if ( nullptr != currentNode ) { // Reconstruct matrix by transform rather than by scale diff --git a/code/PostProcessing/ScaleProcess.h b/code/PostProcessing/ScaleProcess.h index b6eb75de7..ae1c3ed00 100644 --- a/code/PostProcessing/ScaleProcess.h +++ b/code/PostProcessing/ScaleProcess.h @@ -62,11 +62,10 @@ namespace Assimp { */ class ASSIMP_API ScaleProcess : public BaseProcess { public: - /// The default class constructor. + // ------------------------------------------------------------------- + /// The default class constructor / destructor. ScaleProcess(); - - /// The class destructor. - virtual ~ScaleProcess(); + ~ScaleProcess() override = default; /// Will set the scale manually. void setScale( ai_real scale ); @@ -75,13 +74,13 @@ public: ai_real getScale() const; /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; + virtual bool IsActive( unsigned int pFlags ) const override; /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); + virtual void SetupProperties( const Importer* pImp ) override; /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); + virtual void Execute( aiScene* pScene ) override; private: void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 6312fa173..1be75fc48 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -59,10 +59,6 @@ SortByPTypeProcess::SortByPTypeProcess() : // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -SortByPTypeProcess::~SortByPTypeProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool SortByPTypeProcess::IsActive(unsigned int pFlags) const { diff --git a/code/PostProcessing/SortByPTypeProcess.h b/code/PostProcessing/SortByPTypeProcess.h index e30342a86..ce4f7da62 100644 --- a/code/PostProcessing/SortByPTypeProcess.h +++ b/code/PostProcessing/SortByPTypeProcess.h @@ -60,17 +60,19 @@ namespace Assimp { */ class ASSIMP_API SortByPTypeProcess : public BaseProcess { public: + // ------------------------------------------------------------------- + /// The default class constructor / destructor. SortByPTypeProcess(); - ~SortByPTypeProcess(); + ~SortByPTypeProcess() override = default; // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; private: int mConfigRemoveMeshes; diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index a501d3bd6..5324160d4 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -40,7 +40,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - /// @file SplitByBoneCountProcess.cpp /// Implementation of the SplitByBoneCount postprocessing step @@ -59,47 +58,36 @@ using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ // Constructor -SplitByBoneCountProcess::SplitByBoneCountProcess() -{ - // set default, might be overridden by importer config - mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES; +SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) { + // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor -SplitByBoneCountProcess::~SplitByBoneCountProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag. -bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const -{ +bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const { return !!(pFlags & aiProcess_SplitByBoneCount); } // ------------------------------------------------------------------------------------------------ // Updates internal properties -void SplitByBoneCountProcess::SetupProperties(const Importer* pImp) -{ +void SplitByBoneCountProcess::SetupProperties(const Importer* pImp) { mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void SplitByBoneCountProcess::Execute( aiScene* pScene) -{ +void SplitByBoneCountProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin"); // early out bool isNecessary = false; for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) - { + if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) { isNecessary = true; break; } - if( !isNecessary ) - { + if( !isNecessary ) { ASSIMP_LOG_DEBUG("SplitByBoneCountProcess early-out: no meshes with more than ", mMaxBoneCount, " bones." ); return; } @@ -111,28 +99,23 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene) // build a new array of meshes for the scene std::vector meshes; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - { + for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) { aiMesh* srcMesh = pScene->mMeshes[a]; std::vector newMeshes; SplitMesh( pScene->mMeshes[a], newMeshes); // mesh was split - if( !newMeshes.empty() ) - { + if( !newMeshes.empty() ) { // store new meshes and indices of the new meshes - for( unsigned int b = 0; b < newMeshes.size(); ++b) - { + for( unsigned int b = 0; b < newMeshes.size(); ++b) { mSubMeshIndices[a].push_back( static_cast(meshes.size())); meshes.push_back( newMeshes[b]); } // and destroy the source mesh. It should be completely contained inside the new submeshes delete srcMesh; - } - else - { + } else { // Mesh is kept unchanged - store it's new place in the mesh array mSubMeshIndices[a].push_back( static_cast(meshes.size())); meshes.push_back( srcMesh); @@ -153,11 +136,9 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene) // ------------------------------------------------------------------------------------------------ // Splits the given mesh by bone count. -void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector& poNewMeshes) const -{ +void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector& poNewMeshes) const { // skip if not necessary - if( pMesh->mNumBones <= mMaxBoneCount ) - { + if( pMesh->mNumBones <= mMaxBoneCount ) { return; } @@ -165,27 +146,22 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector BoneWeight; std::vector< std::vector > vertexBones( pMesh->mNumVertices); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a) - { + for( unsigned int a = 0; a < pMesh->mNumBones; ++a) { const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; ++b) - { - if (bone->mWeights[b].mWeight > 0.0f) - { - int vertexId = bone->mWeights[b].mVertexId; - vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight); - if (vertexBones[vertexId].size() > mMaxBoneCount) - { - throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!"); + for( unsigned int b = 0; b < bone->mNumWeights; ++b) { + if (bone->mWeights[b].mWeight > 0.0f) { + int vertexId = bone->mWeights[b].mVertexId; + vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight); + if (vertexBones[vertexId].size() > mMaxBoneCount) { + throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!"); + } } - } } } unsigned int numFacesHandled = 0; std::vector isFaceHandled( pMesh->mNumFaces, false); - while( numFacesHandled < pMesh->mNumFaces ) - { + while( numFacesHandled < pMesh->mNumFaces ) { // which bones are used in the current submesh unsigned int numBones = 0; std::vector isBoneUsed( pMesh->mNumBones, false); @@ -196,11 +172,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumFaces; ++a) - { + for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) { // skip if the face is already stored in a submesh - if( isFaceHandled[a] ) - { + if( isFaceHandled[a] ) { continue; } // a small local set of new bones for the current face. State of all used bones for that face @@ -209,33 +183,27 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormFaces[a]; // check every vertex if its bones would still fit into the current submesh - for( unsigned int b = 0; b < face.mNumIndices; ++b ) - { - const std::vector& vb = vertexBones[face.mIndices[b]]; - for( unsigned int c = 0; c < vb.size(); ++c) - { - unsigned int boneIndex = vb[c].first; - if( !isBoneUsed[boneIndex] ) - { - newBonesAtCurrentFace.insert(boneIndex); + for( unsigned int b = 0; b < face.mNumIndices; ++b ) { + const std::vector& vb = vertexBones[face.mIndices[b]]; + for( unsigned int c = 0; c < vb.size(); ++c) { + unsigned int boneIndex = vb[c].first; + if( !isBoneUsed[boneIndex] ) { + newBonesAtCurrentFace.insert(boneIndex); + } } - } } // leave out the face if the new bones required for this face don't fit the bone count limit anymore - if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) - { + if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) { continue; } // mark all new bones as necessary - for (std::set::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) - { - if (!isBoneUsed[*it]) - { - isBoneUsed[*it] = true; - numBones++; - } + for (std::set::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) { + if (!isBoneUsed[*it]) { + isBoneUsed[*it] = true; + numBones++; + } } // store the face index and the vertex count @@ -261,27 +229,21 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumVertices = numSubMeshVertices; newMesh->mNumFaces = static_cast(subMeshFaces.size()); newMesh->mVertices = new aiVector3D[newMesh->mNumVertices]; - if( pMesh->HasNormals() ) - { + if( pMesh->HasNormals() ) { newMesh->mNormals = new aiVector3D[newMesh->mNumVertices]; } - if( pMesh->HasTangentsAndBitangents() ) - { + if( pMesh->HasTangentsAndBitangents() ) { newMesh->mTangents = new aiVector3D[newMesh->mNumVertices]; newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices]; } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( pMesh->HasTextureCoords( a) ) - { + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { + if( pMesh->HasTextureCoords( a) ) { newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices]; } newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) - { - if( pMesh->HasVertexColors( a) ) - { + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) { + if( pMesh->HasVertexColors( a) ) { newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices]; } } @@ -290,41 +252,33 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormFaces = new aiFace[subMeshFaces.size()]; unsigned int nvi = 0; // next vertex index std::vector previousVertexIndices( numSubMeshVertices, std::numeric_limits::max()); // per new vertex: its index in the source mesh - for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) - { + for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) { const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; aiFace& dstFace = newMesh->mFaces[a]; dstFace.mNumIndices = srcFace.mNumIndices; dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; // accumulate linearly all the vertices of the source face - for( unsigned int b = 0; b < dstFace.mNumIndices; ++b ) - { + for( unsigned int b = 0; b < dstFace.mNumIndices; ++b ) { unsigned int srcIndex = srcFace.mIndices[b]; dstFace.mIndices[b] = nvi; previousVertexIndices[nvi] = srcIndex; newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; - if( pMesh->HasNormals() ) - { + if( pMesh->HasNormals() ) { newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; } - if( pMesh->HasTangentsAndBitangents() ) - { + if( pMesh->HasTangentsAndBitangents() ) { newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) - { - if( pMesh->HasTextureCoords( c) ) - { + for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) { + if( pMesh->HasTextureCoords( c) ) { newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; } } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) - { - if( pMesh->HasVertexColors( c) ) - { + for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) { + if( pMesh->HasVertexColors( c) ) { newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; } } @@ -340,10 +294,8 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormBones = new aiBone*[numBones]; std::vector mappedBoneIndex( pMesh->mNumBones, std::numeric_limits::max()); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) - { - if( !isBoneUsed[a] ) - { + for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) { + if( !isBoneUsed[a] ) { continue; } @@ -360,24 +312,20 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumBones == numBones ); // iterate over all new vertices and count which bones affected its old vertex in the source mesh - for( unsigned int a = 0; a < numSubMeshVertices; ++a ) - { + for( unsigned int a = 0; a < numSubMeshVertices; ++a ) { unsigned int oldIndex = previousVertexIndices[a]; const std::vector& bonesOnThisVertex = vertexBones[oldIndex]; - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b ) - { + for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b ) { unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; - if( newBoneIndex != std::numeric_limits::max() ) - { + if( newBoneIndex != std::numeric_limits::max() ) { newMesh->mBones[newBoneIndex]->mNumWeights++; } } } // allocate all bone weight arrays accordingly - for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) - { + for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) { aiBone* bone = newMesh->mBones[a]; ai_assert( bone->mNumWeights > 0 ); bone->mWeights = new aiVertexWeight[bone->mNumWeights]; @@ -385,16 +333,14 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector& bonesOnThisVertex = vertexBones[previousIndex]; // all of the bones affecting it should be present in the new submesh, or else // the face it comprises shouldn't be present - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b) - { + for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b) { unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; ai_assert( newBoneIndex != std::numeric_limits::max() ); aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights; @@ -450,14 +396,11 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumMeshes > 0 ) - { + if( pNode->mNumMeshes == 0 ) { std::vector newMeshList; - for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) - { + for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) { unsigned int srcIndex = pNode->mMeshes[a]; const std::vector& replaceMeshes = mSubMeshIndices[srcIndex]; newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); @@ -470,8 +413,7 @@ void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const } // do that also recursively for all children - for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) - { + for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) { UpdateNode( pNode->mChildren[a]); } } diff --git a/code/PostProcessing/SplitByBoneCountProcess.h b/code/PostProcessing/SplitByBoneCountProcess.h index 938b00c7f..625019e0c 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.h +++ b/code/PostProcessing/SplitByBoneCountProcess.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2022, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -51,9 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace Assimp -{ - +namespace Assimp { /** Postprocessing filter to split meshes with many bones into submeshes * so that each submesh has a certain max bone count. @@ -61,34 +58,29 @@ namespace Assimp * Applied BEFORE the JoinVertices-Step occurs. * Returns NON-UNIQUE vertices, splits by bone count. */ -class SplitByBoneCountProcess : public BaseProcess -{ +class SplitByBoneCountProcess : public BaseProcess { public: - + // ------------------------------------------------------------------- + /// The default class constructor / destructor. SplitByBoneCountProcess(); - ~SplitByBoneCountProcess(); + ~SplitByBoneCountProcess() override = default; -public: - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; + /// @brief Returns whether the processing step is present in the given flag. + /// @param pFlags The processing flags the importer was called with. A + /// bitwise combination of #aiPostProcessSteps. + /// @return true if the process is present in this flag fields, false if not. + bool IsActive( unsigned int pFlags) const override; - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); + /// @brief Called prior to ExecuteOnScene(). + /// The function is a request to the process to update its configuration + /// basing on the Importer's configuration property list. + virtual void SetupProperties(const Importer* pImp) override; protected: - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); + /// Executes the post processing step on the given imported data. + /// At the moment a process is not supposed to fail. + /// @param pScene The imported data to work at. + void Execute( aiScene* pScene) override; /// Splits the given mesh by bone count. /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. diff --git a/code/PostProcessing/SplitLargeMeshes.cpp b/code/PostProcessing/SplitLargeMeshes.cpp index 151ac4991..73e0cc5d8 100644 --- a/code/PostProcessing/SplitLargeMeshes.cpp +++ b/code/PostProcessing/SplitLargeMeshes.cpp @@ -55,9 +55,6 @@ SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() { LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; } -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const { @@ -329,9 +326,6 @@ SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() { LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; } -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const { diff --git a/code/PostProcessing/SplitLargeMeshes.h b/code/PostProcessing/SplitLargeMeshes.h index e5a8d4c1b..4e0d764c1 100644 --- a/code/PostProcessing/SplitLargeMeshes.h +++ b/code/PostProcessing/SplitLargeMeshes.h @@ -83,16 +83,15 @@ class SplitLargeMeshesProcess_Vertex; * Applied BEFORE the JoinVertices-Step occurs. * Returns NON-UNIQUE vertices, splits by triangle number. */ -class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess -{ +class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess { friend class SplitLargeMeshesProcess_Vertex; public: - + // ------------------------------------------------------------------- + /// The default class constructor / destructor. SplitLargeMeshesProcess_Triangle(); - ~SplitLargeMeshesProcess_Triangle(); + ~SplitLargeMeshesProcess_Triangle() override = default; -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. A @@ -100,16 +99,14 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - bool IsActive( unsigned int pFlags) const; - + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); - + void SetupProperties(const Importer* pImp) override; //! Set the split limit - needed for unit testing inline void SetLimit(unsigned int l) @@ -119,14 +116,12 @@ public: inline unsigned int GetLimit() const {return LIMIT;} -public: - // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- //! Apply the algorithm to a given mesh @@ -144,36 +139,31 @@ public: unsigned int LIMIT; }; - // --------------------------------------------------------------------------- /** Post-processing filter to split large meshes into sub-meshes * * Applied AFTER the JoinVertices-Step occurs. * Returns UNIQUE vertices, splits by vertex number. */ -class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess -{ +class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess { public: - SplitLargeMeshesProcess_Vertex(); - ~SplitLargeMeshesProcess_Vertex(); + ~SplitLargeMeshesProcess_Vertex() override = default; -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); - + void SetupProperties(const Importer* pImp) override; //! Set the split limit - needed for unit testing inline void SetLimit(unsigned int l) @@ -183,14 +173,12 @@ public: inline unsigned int GetLimit() const {return LIMIT;} -public: - // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- //! Apply the algorithm to a given mesh diff --git a/code/PostProcessing/TextureTransform.cpp b/code/PostProcessing/TextureTransform.cpp index efbf4d2c6..2ed17f390 100644 --- a/code/PostProcessing/TextureTransform.cpp +++ b/code/PostProcessing/TextureTransform.cpp @@ -56,33 +56,24 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -TextureTransformStep::TextureTransformStep() : - configFlags() -{ +TextureTransformStep::TextureTransformStep() : configFlags() { // nothing to do here } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TextureTransformStep::~TextureTransformStep() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool TextureTransformStep::IsActive( unsigned int pFlags) const -{ +bool TextureTransformStep::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_TransformUVCoords) != 0; } // ------------------------------------------------------------------------------------------------ // Setup properties -void TextureTransformStep::SetupProperties(const Importer* pImp) -{ +void TextureTransformStep::SetupProperties(const Importer* pImp) { configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL); } // ------------------------------------------------------------------------------------------------ -void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) -{ +void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) { /* This function tries to simplify the input UV transformation. * That's very important as it allows us to reduce the number * of output UV channels. The order in which the transformations @@ -90,7 +81,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) */ int rounded; - char szTemp[512]; + char szTemp[512] = {}; /* Optimize the rotation angle. That's slightly difficult as * we have an inprecise floating-point number (when comparing @@ -98,12 +89,10 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) * an epsilon of 5 degrees). If there is a rotation value, we can't * perform any further optimizations. */ - if (info.mRotation) - { + if (info.mRotation) { float out = info.mRotation; rounded = static_cast((info.mRotation / static_cast(AI_MATH_TWO_PI))); - if (rounded) - { + if (rounded) { out -= rounded * static_cast(AI_MATH_PI); ASSIMP_LOG_INFO("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out); } @@ -187,8 +176,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) } // ------------------------------------------------------------------------------------------------ -void UpdateUVIndex(const std::list& l, unsigned int n) -{ +void UpdateUVIndex(const std::list& l, unsigned int n) { // Don't set if == 0 && wasn't set before for (std::list::const_iterator it = l.begin();it != l.end(); ++it) { const TTUpdateInfo& info = *it; @@ -203,8 +191,7 @@ void UpdateUVIndex(const std::list& l, unsigned int n) } // ------------------------------------------------------------------------------------------------ -inline const char* MappingModeToChar(aiTextureMapMode map) -{ +inline static const char* MappingModeToChar(aiTextureMapMode map) { if (aiTextureMapMode_Wrap == map) return "-w"; @@ -215,8 +202,7 @@ inline const char* MappingModeToChar(aiTextureMapMode map) } // ------------------------------------------------------------------------------------------------ -void TextureTransformStep::Execute( aiScene* pScene) -{ +void TextureTransformStep::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin"); diff --git a/code/PostProcessing/TextureTransform.h b/code/PostProcessing/TextureTransform.h index c1cccf8ef..c9f0480ba 100644 --- a/code/PostProcessing/TextureTransform.h +++ b/code/PostProcessing/TextureTransform.h @@ -193,28 +193,23 @@ struct STransformVecInfo : public aiUVTransform { /** Helper step to compute final UV coordinate sets if there are scalings * or rotations in the original data read from the file. */ -class TextureTransformStep : public BaseProcess -{ +class TextureTransformStep : public BaseProcess { public: - + // ------------------------------------------------------------------- + /// The default class constructor / destructor. TextureTransformStep(); - ~TextureTransformStep(); - -public: + ~TextureTransformStep() override = default; // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - + void SetupProperties(const Importer* pImp) override; protected: - - // ------------------------------------------------------------------- /** Preprocess a specific UV transformation setup * @@ -223,10 +218,9 @@ protected: void PreProcessUVTransform(STransformVecInfo& info); private: - unsigned int configFlags; }; - -} + +} // namespace Assimp #endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED diff --git a/code/PostProcessing/TriangulateProcess.cpp b/code/PostProcessing/TriangulateProcess.cpp index 52e760361..52cfa66bf 100644 --- a/code/PostProcessing/TriangulateProcess.cpp +++ b/code/PostProcessing/TriangulateProcess.cpp @@ -156,15 +156,6 @@ namespace { } - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TriangulateProcess::TriangulateProcess() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TriangulateProcess::~TriangulateProcess() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool TriangulateProcess::IsActive( unsigned int pFlags) const @@ -468,6 +459,21 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) continue; } + // Skip when three point is in a line + aiVector2D left = *pnt0 - *pnt1; + aiVector2D right = *pnt2 - *pnt1; + + left.Normalize(); + right.Normalize(); + auto mul = left * right; + + // if the angle is 0 or 180 + if (std::abs(mul - 1.f) < ai_epsilon || std::abs(mul + 1.f) < ai_epsilon) { + // skip this ear + ASSIMP_LOG_WARN("Skip a ear, due to its angle is near 0 or 180."); + continue; + } + // and no other point may be contained in this triangle for ( tmp = 0; tmp < max; ++tmp) { diff --git a/code/PostProcessing/TriangulateProcess.h b/code/PostProcessing/TriangulateProcess.h index ed5f4a587..ac31e4377 100644 --- a/code/PostProcessing/TriangulateProcess.h +++ b/code/PostProcessing/TriangulateProcess.h @@ -61,8 +61,10 @@ namespace Assimp { */ class ASSIMP_API TriangulateProcess : public BaseProcess { public: - TriangulateProcess(); - ~TriangulateProcess(); + // ------------------------------------------------------------------- + /// The default class constructor / destructor. + TriangulateProcess() = default; + ~TriangulateProcess() override = default; // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. @@ -70,14 +72,14 @@ public: * combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, false if not. */ - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- /** Triangulates the given mesh. diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index d234e220b..e31054972 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -60,12 +60,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ValidateDSProcess::ValidateDSProcess() : - mScene() {} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ValidateDSProcess::~ValidateDSProcess() = default; +ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. @@ -916,7 +911,12 @@ void ValidateDSProcess::Validate(const aiNode *pNode) { nodeName, pNode->mNumChildren); } for (unsigned int i = 0; i < pNode->mNumChildren; ++i) { - Validate(pNode->mChildren[i]); + const aiNode *pChild = pNode->mChildren[i]; + Validate(pChild); + if (pChild->mParent != pNode) { + const char *parentName = (pChild->mParent != nullptr) ? pChild->mParent->mName.C_Str() : "null"; + ReportError("aiNode \"%s\" child %i \"%s\" parent is someone else: \"%s\"", pNode->mName.C_Str(), i, pChild->mName.C_Str(), parentName); + } } } } diff --git a/code/PostProcessing/ValidateDataStructure.h b/code/PostProcessing/ValidateDataStructure.h index 077a47b70..9cfd4ced1 100644 --- a/code/PostProcessing/ValidateDataStructure.h +++ b/code/PostProcessing/ValidateDataStructure.h @@ -69,22 +69,20 @@ namespace Assimp { /** Validates the whole ASSIMP scene data structure for correctness. * ImportErrorException is thrown of the scene is corrupt.*/ // -------------------------------------------------------------------------------------- -class ValidateDSProcess : public BaseProcess -{ +class ValidateDSProcess : public BaseProcess { public: - + // ------------------------------------------------------------------- + /// The default class constructor / destructor. ValidateDSProcess(); - ~ValidateDSProcess(); - -public: - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + ~ValidateDSProcess() override = default; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + bool IsActive( unsigned int pFlags) const override; + + // ------------------------------------------------------------------- + void Execute( aiScene* pScene) override; protected: - // ------------------------------------------------------------------- /** Report a validation error. This will throw an exception, * control won't return. diff --git a/contrib/stb/stb_image.h b/contrib/stb/stb_image.h index 8d173c66a..5e807a0a6 100644 --- a/contrib/stb/stb_image.h +++ b/contrib/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,8 @@ LICENSE RECENT REVISION HISTORY: + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically @@ -89,7 +91,7 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera @@ -102,19 +104,21 @@ RECENT REVISION HISTORY: Thomas Ruf Ronny Chevalier github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton github:snagar + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko [reserved] + Brad Weinberger Matvey Cherevko github:mosra Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME HERE + Jacko Dirks + To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end of the credits. @@ -137,7 +141,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -176,6 +180,32 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// // =========================================================================== // // UNICODE: @@ -281,11 +311,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -489,6 +518,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // as above, but only applies to images loaded on the thread that calls the function // this function is only available if your compiler supports thread-local variables; // calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes @@ -605,7 +636,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #endif #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -634,7 +665,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -748,9 +779,12 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif +#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name @@ -924,6 +958,7 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif static @@ -998,7 +1033,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && @@ -1021,7 +1056,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; @@ -1029,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two signed shorts is valid, 0 on overflow. +static int stbi__mul2shorts_valid(short a, short b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1087,9 +1139,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1107,6 +1158,13 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1262,12 +1320,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1277,16 +1335,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1662,7 +1720,8 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif @@ -1944,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -2071,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -2089,14 +2153,14 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -2104,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -2115,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2146,14 +2212,16 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2167,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2203,12 +2272,14 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); - if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2242,10 +2313,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2263,7 +2335,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -3062,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3227,6 +3300,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; @@ -3304,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + while (x == 255) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3320,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3782,6 +3881,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // resample and color-convert { int k; @@ -3924,6 +4027,8 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3936,6 +4041,8 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -3960,6 +4067,8 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -3979,6 +4088,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -3988,8 +4098,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -4120,7 +4230,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if ((unsigned int)b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; @@ -4201,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) a->zout = zout; return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); @@ -4317,7 +4428,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4363,7 +4474,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4759,6 +4870,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4879,19 +4991,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = flag_true_if_should_convert; } +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -4941,7 +5080,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; stbi_uc has_trans=0, tc[3]={0}; - stbi__uint16 tc16[3]={0}; + stbi__uint16 tc16[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; int first=1,k,interlace=0, color=0, is_iphone=0; stbi__context *s = z->s; @@ -4981,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5020,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { @@ -5032,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -5272,6 +5418,32 @@ typedef struct int extra_read; } stbi__bmp_data; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5299,6 +5471,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5313,17 +5487,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); @@ -5338,6 +5502,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { + // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5345,6 +5510,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5394,9 +5561,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); - if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); } } @@ -6342,6 +6522,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6457,6 +6638,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6766,6 +6948,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { @@ -6775,6 +6968,12 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, stbi_uc *two_back = 0; stbi__gif g; int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + memset(&g, 0, sizeof(g)); if (delays) { *delays = 0; @@ -6791,24 +6990,31 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, stride = g.w * g.h * 4; if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); - if (NULL == tmp) { - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - return stbi__errpuc("outofmem", "Out of memory"); - } + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); else { out = (stbi_uc*) tmp; + out_size = layers * stride; } if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); } } else { out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; if (delays) { *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); } } memcpy( out + ((layers - 1) * stride), u, stride ); @@ -7058,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -7132,9 +7338,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7200,8 +7407,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - (void) stbi__get32be(s); - (void) stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7280,7 +7487,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7301,7 +7507,8 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) return 0; if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); @@ -7311,15 +7518,22 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7356,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7386,17 +7602,29 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; else - return 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7452,6 +7680,9 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif return 0; } diff --git a/contrib/unzip/crypt.c b/contrib/unzip/crypt.c index 4cc731b3e..cc6650630 100644 --- a/contrib/unzip/crypt.c +++ b/contrib/unzip/crypt.c @@ -103,7 +103,7 @@ int cryptrand(unsigned char *buf, unsigned int len) unsigned __int64 pentium_tsc[1]; int result = 0; - + #if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { result = CryptGenRandom(provider, len, buf); @@ -111,6 +111,7 @@ int cryptrand(unsigned char *buf, unsigned int len) if (result) return len; } + #endif for (rlen = 0; rlen < (int)len; ++rlen) { diff --git a/contrib/zlib/CMakeLists.txt b/contrib/zlib/CMakeLists.txt index 469151ff6..5bc2d6065 100644 --- a/contrib/zlib/CMakeLists.txt +++ b/contrib/zlib/CMakeLists.txt @@ -76,7 +76,15 @@ if(MSVC) set(CMAKE_DEBUG_POSTFIX "d") add_definitions(-D_CRT_SECURE_NO_DEPRECATE) add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-non-prototype") + endif() + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +else() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-non-prototype") + endif() endif() if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) @@ -88,7 +96,7 @@ if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) message(STATUS "to 'zconf.h.included' because this file is included with zlib") message(STATUS "but CMake generates it automatically in the build directory.") file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included) - endif() + endif() endif() set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) diff --git a/port/PyAssimp/pyassimp/core.py b/port/PyAssimp/pyassimp/core.py index 35ad882b3..edde8b29a 100644 --- a/port/PyAssimp/pyassimp/core.py +++ b/port/PyAssimp/pyassimp/core.py @@ -115,6 +115,10 @@ def _init(self, target = None, parent = None): if m.startswith("_"): continue + # We should not be accessing `mPrivate` according to structs.Scene. + if m == 'mPrivate': + continue + if m.startswith('mNum'): if 'm' + m[4:] in dirself: continue # will be processed later on @@ -211,7 +215,7 @@ def _init(self, target = None, parent = None): else: # starts with 'm' but not iterable - setattr(target, m, obj) + setattr(target, name, obj) logger.debug("Added " + name + " as self." + name + " (type: " + str(type(obj)) + ")") if _is_init_type(obj): diff --git a/test/models-nonbsd/BLEND/guard1_body.png b/test/models-nonbsd/BLEND/guard1_body.png new file mode 100644 index 000000000..2eb3f2caa Binary files /dev/null and b/test/models-nonbsd/BLEND/guard1_body.png differ diff --git a/test/models-nonbsd/BLEND/guard1_face.png b/test/models-nonbsd/BLEND/guard1_face.png new file mode 100644 index 000000000..b7e17d375 Binary files /dev/null and b/test/models-nonbsd/BLEND/guard1_face.png differ diff --git a/test/models-nonbsd/BLEND/guard1_helmet.png b/test/models-nonbsd/BLEND/guard1_helmet.png new file mode 100644 index 000000000..166d790fd Binary files /dev/null and b/test/models-nonbsd/BLEND/guard1_helmet.png differ diff --git a/test/models-nonbsd/BLEND/iron_grill.png b/test/models-nonbsd/BLEND/iron_grill.png new file mode 100644 index 000000000..53a3bbbcc Binary files /dev/null and b/test/models-nonbsd/BLEND/iron_grill.png differ diff --git a/test/models-nonbsd/BLEND/round_grill.png b/test/models-nonbsd/BLEND/round_grill.png new file mode 100644 index 000000000..502a1d782 Binary files /dev/null and b/test/models-nonbsd/BLEND/round_grill.png differ diff --git a/test/models-nonbsd/IRR/skybox.xml b/test/models-nonbsd/IRR/skybox.xml index a572e473f..a2be5b785 100644 Binary files a/test/models-nonbsd/IRR/skybox.xml and b/test/models-nonbsd/IRR/skybox.xml differ diff --git a/test/models-nonbsd/IRR/skybox_UTF16LE.xml b/test/models-nonbsd/IRR/skybox_UTF16LE.xml new file mode 100644 index 000000000..a572e473f Binary files /dev/null and b/test/models-nonbsd/IRR/skybox_UTF16LE.xml differ diff --git a/test/models/COB/axe.jpg b/test/models/COB/axe.jpg new file mode 100644 index 000000000..ba14ae0ea Binary files /dev/null and b/test/models/COB/axe.jpg differ diff --git a/test/models/COB/dwarf.jpg b/test/models/COB/dwarf.jpg new file mode 100644 index 000000000..9c07e0038 Binary files /dev/null and b/test/models/COB/dwarf.jpg differ diff --git a/test/models/COB/dwarf2.jpg b/test/models/COB/dwarf2.jpg new file mode 100644 index 000000000..cf54b0657 Binary files /dev/null and b/test/models/COB/dwarf2.jpg differ diff --git a/test/models/IRR/1.png b/test/models/IRR/1.png new file mode 100644 index 000000000..e7200658b Binary files /dev/null and b/test/models/IRR/1.png differ diff --git a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr index 1f0916d4d..94d0bae6f 100644 Binary files a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr and b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr differ diff --git a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr new file mode 100644 index 000000000..1f0916d4d Binary files /dev/null and b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr differ diff --git a/test/models/IRR/EpisodeI_ANewDwarf.irr b/test/models/IRR/EpisodeI_ANewDwarf.irr index 39d99e440..6daeec96c 100644 Binary files a/test/models/IRR/EpisodeI_ANewDwarf.irr and b/test/models/IRR/EpisodeI_ANewDwarf.irr differ diff --git a/test/models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr b/test/models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr new file mode 100644 index 000000000..39d99e440 Binary files /dev/null and b/test/models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr differ diff --git a/test/models/IRR/animMesh.irr b/test/models/IRR/animMesh.irr index d1c9e1018..c1c247ff2 100644 Binary files a/test/models/IRR/animMesh.irr and b/test/models/IRR/animMesh.irr differ diff --git a/test/models/IRR/animMesh_UTF16LE.irr b/test/models/IRR/animMesh_UTF16LE.irr new file mode 100644 index 000000000..d1c9e1018 Binary files /dev/null and b/test/models/IRR/animMesh_UTF16LE.irr differ diff --git a/test/models/IRR/box.irr b/test/models/IRR/box.irr index efc165d93..8a094ded6 100644 Binary files a/test/models/IRR/box.irr and b/test/models/IRR/box.irr differ diff --git a/test/models/IRR/box_UTF16LE.irr b/test/models/IRR/box_UTF16LE.irr new file mode 100644 index 000000000..efc165d93 Binary files /dev/null and b/test/models/IRR/box_UTF16LE.irr differ diff --git a/test/models/IRR/brownground_1-1.jpg b/test/models/IRR/brownground_1-1.jpg new file mode 100644 index 000000000..fda7d45c6 Binary files /dev/null and b/test/models/IRR/brownground_1-1.jpg differ diff --git a/test/models/IRR/crackedground_1-6.jpg b/test/models/IRR/crackedground_1-6.jpg new file mode 100644 index 000000000..48da577fd Binary files /dev/null and b/test/models/IRR/crackedground_1-6.jpg differ diff --git a/test/models/IRR/dawfInCellar_ChildOfCellar.irr b/test/models/IRR/dawfInCellar_ChildOfCellar.irr index 698530d3a..fd2c80ae7 100644 Binary files a/test/models/IRR/dawfInCellar_ChildOfCellar.irr and b/test/models/IRR/dawfInCellar_ChildOfCellar.irr differ diff --git a/test/models/IRR/dawfInCellar_ChildOfCellar_UTF16LE.irr b/test/models/IRR/dawfInCellar_ChildOfCellar_UTF16LE.irr new file mode 100644 index 000000000..698530d3a Binary files /dev/null and b/test/models/IRR/dawfInCellar_ChildOfCellar_UTF16LE.irr differ diff --git a/test/models/IRR/dawfInCellar_SameHierarchy.irr b/test/models/IRR/dawfInCellar_SameHierarchy.irr index 83d4ab932..5fbfbe655 100644 Binary files a/test/models/IRR/dawfInCellar_SameHierarchy.irr and b/test/models/IRR/dawfInCellar_SameHierarchy.irr differ diff --git a/test/models/IRR/dawfInCellar_SameHierarchy_UTF16LE.irr b/test/models/IRR/dawfInCellar_SameHierarchy_UTF16LE.irr new file mode 100644 index 000000000..83d4ab932 Binary files /dev/null and b/test/models/IRR/dawfInCellar_SameHierarchy_UTF16LE.irr differ diff --git a/test/models/IRR/multipleAnimators.irr b/test/models/IRR/multipleAnimators.irr index fb468aa11..9e4bc4b7c 100644 Binary files a/test/models/IRR/multipleAnimators.irr and b/test/models/IRR/multipleAnimators.irr differ diff --git a/test/models/IRR/multipleAnimators_UTF16LE.irr b/test/models/IRR/multipleAnimators_UTF16LE.irr new file mode 100644 index 000000000..fb468aa11 Binary files /dev/null and b/test/models/IRR/multipleAnimators_UTF16LE.irr differ diff --git a/test/models/IRR/scenegraphAnim.irr b/test/models/IRR/scenegraphAnim.irr index 3cf28a960..ff7a612e0 100644 Binary files a/test/models/IRR/scenegraphAnim.irr and b/test/models/IRR/scenegraphAnim.irr differ diff --git a/test/models/IRR/scenegraphAnim_UTF16LE.irr b/test/models/IRR/scenegraphAnim_UTF16LE.irr new file mode 100644 index 000000000..3cf28a960 Binary files /dev/null and b/test/models/IRR/scenegraphAnim_UTF16LE.irr differ diff --git a/test/models/IRR/sphere.irr b/test/models/IRR/sphere.irr index ab4219268..f21e8f133 100644 Binary files a/test/models/IRR/sphere.irr and b/test/models/IRR/sphere.irr differ diff --git a/test/models/IRR/sphere_UTF16LE.irr b/test/models/IRR/sphere_UTF16LE.irr new file mode 100644 index 000000000..ab4219268 Binary files /dev/null and b/test/models/IRR/sphere_UTF16LE.irr differ diff --git a/test/models/IRRMesh/cellar.irrmesh b/test/models/IRRMesh/cellar.irrmesh index d8d3a661b..0278c9239 100644 Binary files a/test/models/IRRMesh/cellar.irrmesh and b/test/models/IRRMesh/cellar.irrmesh differ diff --git a/test/models/IRRMesh/cellar_UTF16LE.irrmesh b/test/models/IRRMesh/cellar_UTF16LE.irrmesh new file mode 100644 index 000000000..d8d3a661b Binary files /dev/null and b/test/models/IRRMesh/cellar_UTF16LE.irrmesh differ diff --git a/test/models/IRRMesh/spider.irrmesh b/test/models/IRRMesh/spider.irrmesh index c6ad9291f..f956130e1 100644 Binary files a/test/models/IRRMesh/spider.irrmesh and b/test/models/IRRMesh/spider.irrmesh differ diff --git a/test/models/IRRMesh/spider_UTF16LE.irrmesh b/test/models/IRRMesh/spider_UTF16LE.irrmesh new file mode 100644 index 000000000..c6ad9291f Binary files /dev/null and b/test/models/IRRMesh/spider_UTF16LE.irrmesh differ diff --git a/test/models/IRRMesh/testFormatDetection.xml b/test/models/IRRMesh/testFormatDetection.xml index aa73560d4..0986eaf61 100644 Binary files a/test/models/IRRMesh/testFormatDetection.xml and b/test/models/IRRMesh/testFormatDetection.xml differ diff --git a/test/models/IRRMesh/testFormatDetection_UTF16LE.xml b/test/models/IRRMesh/testFormatDetection_UTF16LE.xml new file mode 100644 index 000000000..aa73560d4 Binary files /dev/null and b/test/models/IRRMesh/testFormatDetection_UTF16LE.xml differ diff --git a/test/models/MDL/MDL (HL1)/multiple_roots.mdl b/test/models/MDL/MDL (HL1)/multiple_roots.mdl new file mode 100644 index 000000000..f8fc1eed7 Binary files /dev/null and b/test/models/MDL/MDL (HL1)/multiple_roots.mdl differ diff --git a/test/models/PLY/pond.0.ply b/test/models/PLY/pond.0.ply index 02b7683ce..a45e0322d 100644 Binary files a/test/models/PLY/pond.0.ply and b/test/models/PLY/pond.0.ply differ diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp index 4614066e6..d50c2b35a 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp @@ -190,7 +190,7 @@ private: Assimp::Importer importer; importer.SetPropertyBool(setting_key, setting_value); const aiScene *scene = importer.ReadFile(file_path, aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); func(scene); } diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp index 2389c0ffc..f733893ca 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp @@ -61,8 +61,8 @@ public: void flatShadeTexture() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "chrome_sphere.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); - EXPECT_NE(nullptr, scene->mMaterials); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mMaterials); aiShadingMode shading_mode = aiShadingMode_Flat; scene->mMaterials[0]->Get(AI_MATKEY_SHADING_MODEL, shading_mode); @@ -74,8 +74,8 @@ public: void chromeTexture() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "chrome_sphere.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); - EXPECT_NE(nullptr, scene->mMaterials); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mMaterials); int chrome; scene->mMaterials[0]->Get(AI_MDL_HL1_MATKEY_CHROME(aiTextureType_DIFFUSE, 0), chrome); @@ -87,8 +87,8 @@ public: void additiveBlendTexture() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "blend_additive.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); - EXPECT_NE(nullptr, scene->mMaterials); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mMaterials); aiBlendMode blend_mode = aiBlendMode_Default; scene->mMaterials[0]->Get(AI_MATKEY_BLEND_FUNC, blend_mode); @@ -101,8 +101,8 @@ public: void textureWithColorMask() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "alpha_test.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); - EXPECT_NE(nullptr, scene->mMaterials); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mMaterials); int texture_flags = 0; scene->mMaterials[0]->Get(AI_MATKEY_TEXFLAGS_DIFFUSE(0), texture_flags); diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp index 4420727e9..49ae8a16c 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp @@ -55,6 +55,17 @@ using namespace Assimp; class utMDLImporter_HL1_Nodes : public ::testing::Test { + /** + * @note Represents a flattened node hierarchy where each item is a pair + * containing the node level and it's name. + */ + using Hierarchy = std::vector>; + + /** + * @note A vector of strings. Used for symplifying syntax. + */ + using StringVector = std::vector; + public: /** * @note The following tests require a basic understanding @@ -63,6 +74,51 @@ public: * (Valve Developer Community). */ + // Given a model, verify that the bones nodes hierarchy is correctly formed. + void checkBoneHierarchy() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "multiple_roots.mdl", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene->mRootNode); + + // First, check that "" and "" are linked. + const aiNode* node_MDL_root = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_ROOT); + ASSERT_NE(nullptr, node_MDL_root); + + const aiNode *node_MDL_bones = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONES); + ASSERT_NE(nullptr, node_MDL_bones); + ASSERT_NE(nullptr, node_MDL_bones->mParent); + ASSERT_EQ(node_MDL_root, node_MDL_bones->mParent); + + // Second, verify "" hierarchy. + const Hierarchy expected_hierarchy = { + { 0, AI_MDL_HL1_NODE_BONES }, + { 1, "root1_bone1" }, + { 2, "root1_bone2" }, + { 3, "root1_bone4" }, + { 3, "root1_bone5" }, + { 2, "root1_bone3" }, + { 3, "root1_bone6" }, + { 1, "root2_bone1" }, + { 2, "root2_bone2" }, + { 2, "root2_bone3" }, + { 3, "root2_bone5" }, + { 2, "root2_bone4" }, + { 3, "root2_bone6" }, + { 1, "root3_bone1" }, + { 2, "root3_bone2" }, + { 2, "root3_bone3" }, + { 2, "root3_bone4" }, + { 3, "root3_bone5" }, + { 4, "root3_bone6" }, + { 4, "root3_bone7" }, + }; + + Hierarchy actual_hierarchy; + flatten_hierarchy(node_MDL_bones, actual_hierarchy); + ASSERT_EQ(expected_hierarchy, actual_hierarchy); + } + /* Given a model with bones that have empty names, verify that all the bones of the imported model have unique and no empty names. @@ -80,9 +136,9 @@ public: void emptyBonesNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_bones.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_bones_names = { + const StringVector expected_bones_names = { "Bone", "Bone_0", "Bone_1", @@ -94,7 +150,9 @@ public: "Bone_7" }; - expect_named_children(scene, AI_MDL_HL1_NODE_BONES, expected_bones_names); + StringVector actual_bones_names; + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONES), actual_bones_names); + ASSERT_EQ(expected_bones_names, actual_bones_names); } /* Given a model with bodyparts that have empty names, @@ -114,9 +172,9 @@ public: void emptyBodypartsNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_bodyparts.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_bodyparts_names = { + const StringVector expected_bodyparts_names = { "Bodypart", "Bodypart_1", "Bodypart_5", @@ -128,7 +186,10 @@ public: "Bodypart_7" }; - expect_named_children(scene, AI_MDL_HL1_NODE_BODYPARTS, expected_bodyparts_names); + StringVector actual_bodyparts_names; + // Get the bodyparts names "without" the submodels. + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BODYPARTS), actual_bodyparts_names, 0); + ASSERT_EQ(expected_bodyparts_names, actual_bodyparts_names); } /* Given a model with bodyparts that have duplicate names, @@ -148,9 +209,9 @@ public: void duplicateBodypartsNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_bodyparts.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_bodyparts_names = { + const StringVector expected_bodyparts_names = { "Bodypart", "Bodypart_1", "Bodypart_2", @@ -162,7 +223,10 @@ public: "Bodypart_4" }; - expect_named_children(scene, AI_MDL_HL1_NODE_BODYPARTS, expected_bodyparts_names); + StringVector actual_bodyparts_names; + // Get the bodyparts names "without" the submodels. + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BODYPARTS), actual_bodyparts_names, 0); + ASSERT_EQ(expected_bodyparts_names, actual_bodyparts_names); } /* Given a model with several bodyparts that contains multiple @@ -190,9 +254,9 @@ public: void duplicateSubModelsNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_submodels.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector> expected_bodypart_sub_models_names = { + const std::vector expected_bodypart_sub_models_names = { { "triangle", "triangle_0", @@ -208,11 +272,15 @@ public: }; const aiNode *bodyparts_node = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BODYPARTS); - EXPECT_NE(nullptr, bodyparts_node); + ASSERT_NE(nullptr, bodyparts_node); EXPECT_EQ(3u, bodyparts_node->mNumChildren); - for (unsigned int i = 0; i < bodyparts_node->mNumChildren; ++i) { - expect_named_children(bodyparts_node->mChildren[i], - expected_bodypart_sub_models_names[i]); + + StringVector actual_submodels_names; + for (unsigned int i = 0; i < bodyparts_node->mNumChildren; ++i) + { + actual_submodels_names.clear(); + get_node_children_names(bodyparts_node->mChildren[i], actual_submodels_names); + ASSERT_EQ(expected_bodypart_sub_models_names[i], actual_submodels_names); } } @@ -233,9 +301,9 @@ public: void duplicateSequenceNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_sequences.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_sequence_names = { + const StringVector expected_sequence_names = { "idle_1", "idle", "idle_2", @@ -247,7 +315,9 @@ public: "idle_7" }; - expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_INFOS, expected_sequence_names); + StringVector actual_sequence_names; + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS), actual_sequence_names); + ASSERT_EQ(expected_sequence_names, actual_sequence_names); } /* Given a model with sequences that have empty names, verify @@ -267,9 +337,9 @@ public: void emptySequenceNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_sequences.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_sequence_names = { + const StringVector expected_sequence_names = { "Sequence", "Sequence_1", "Sequence_0", @@ -281,7 +351,9 @@ public: "Sequence_6" }; - expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_INFOS, expected_sequence_names); + StringVector actual_sequence_names; + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS), actual_sequence_names); + ASSERT_EQ(expected_sequence_names, actual_sequence_names); } /* Given a model with sequence groups that have duplicate names, @@ -302,9 +374,9 @@ public: void duplicateSequenceGroupNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "duplicate_sequence_groups/duplicate_sequence_groups.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_sequence_names = { + const StringVector expected_sequence_names = { "default", "SequenceGroup", "SequenceGroup_1", @@ -317,7 +389,9 @@ public: "SequenceGroup_2" }; - expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_GROUPS, expected_sequence_names); + StringVector actual_sequence_names; + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS), actual_sequence_names); + ASSERT_EQ(expected_sequence_names, actual_sequence_names); } /* Given a model with sequence groups that have empty names, @@ -338,9 +412,9 @@ public: void emptySequenceGroupNames() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MDL_HL1_MODELS_DIR "unnamed_sequence_groups/unnamed_sequence_groups.mdl", aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); - const std::vector expected_sequence_names = { + const StringVector expected_sequence_names = { "default", "SequenceGroup", "SequenceGroup_2", @@ -353,7 +427,9 @@ public: "SequenceGroup_4" }; - expect_named_children(scene, AI_MDL_HL1_NODE_SEQUENCE_GROUPS, expected_sequence_names); + StringVector actual_sequence_names; + get_node_children_names(scene->mRootNode->FindNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS), actual_sequence_names); + ASSERT_EQ(expected_sequence_names, actual_sequence_names); } /* Verify that mOffsetMatrix applies the correct @@ -364,7 +440,7 @@ public: Assimp::Importer importer; const aiScene *scene = importer.ReadFile(MDL_HL1_FILE_MAN, aiProcess_ValidateDataStructure); - EXPECT_NE(nullptr, scene); + ASSERT_NE(nullptr, scene); aiNode *scene_bones_node = scene->mRootNode->FindNode(AI_MDL_HL1_NODE_BONES); @@ -398,26 +474,58 @@ public: } private: - void expect_named_children(const aiNode *parent_node, const std::vector &expected_names) { - EXPECT_NE(nullptr, parent_node); - EXPECT_EQ(expected_names.size(), parent_node->mNumChildren); - - for (unsigned int i = 0; i < parent_node->mNumChildren; ++i) - EXPECT_EQ(expected_names[i], parent_node->mChildren[i]->mName.C_Str()); - } - - void expect_named_children(const aiScene *scene, const char *node_name, const std::vector &expected_names) { - expect_named_children(scene->mRootNode->FindNode(node_name), expected_names); - } - void expect_equal_matrices(const aiMatrix4x4 &expected, const aiMatrix4x4 &actual, float abs_error) { for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) EXPECT_NEAR(expected[i][j], actual[i][j], abs_error); } } + + /** Get a flattened representation of a node's hierarchy. + * \param[in] node The node. + * \param[out] hierarchy The flattened node's hierarchy. + */ + void flatten_hierarchy(const aiNode *node, Hierarchy &hierarchy) + { + flatten_hierarchy_impl(node, hierarchy, 0); + } + + void flatten_hierarchy_impl(const aiNode *node, Hierarchy &hierarchy, unsigned int level) + { + hierarchy.push_back({ level, node->mName.C_Str() }); + for (size_t i = 0; i < node->mNumChildren; ++i) + { + flatten_hierarchy_impl(node->mChildren[i], hierarchy, level + 1); + } + } + + /** Get all node's children names beneath max_level. + * \param[in] node The parent node from which to get all children names. + * \param[out] names The list of children names. + * \param[in] max_level If set to -1, all children names will be collected. + */ + void get_node_children_names(const aiNode *node, StringVector &names, const int max_level = -1) + { + get_node_children_names_impl(node, names, 0, max_level); + } + + void get_node_children_names_impl(const aiNode *node, StringVector &names, int level, const int max_level = -1) + { + for (size_t i = 0; i < node->mNumChildren; ++i) + { + names.push_back(node->mChildren[i]->mName.C_Str()); + if (max_level == -1 || level < max_level) + { + get_node_children_names_impl(node->mChildren[i], names, level + 1, max_level); + } + } + } }; +TEST_F(utMDLImporter_HL1_Nodes, checkBoneHierarchy) { + checkBoneHierarchy(); +} + TEST_F(utMDLImporter_HL1_Nodes, emptyBonesNames) { emptyBonesNames(); } diff --git a/test/unit/ut3DImportExport.cpp b/test/unit/ut3DImportExport.cpp index 5ff1d7940..32b77ddf8 100644 --- a/test/unit/ut3DImportExport.cpp +++ b/test/unit/ut3DImportExport.cpp @@ -65,3 +65,24 @@ TEST(ut3DImportExport, importBoxUC) { const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3D/box.uc", aiProcess_ValidateDataStructure); ASSERT_NE(nullptr, scene); } + + +TEST(ut3DImportExport, importMarRifle) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3D/mar_rifle.uc", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST(ut3DImportExport, importMarRifleA) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3D/mar_rifle_a.3d", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST(ut3DImportExport, importMarRifleD) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3D/mar_rifle_d.3d", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} diff --git a/test/unit/ut3DSImportExport.cpp b/test/unit/ut3DSImportExport.cpp index 01406362d..7279227fc 100644 --- a/test/unit/ut3DSImportExport.cpp +++ b/test/unit/ut3DSImportExport.cpp @@ -70,3 +70,115 @@ TEST_F(ut3DSImportExport, import3DSformatdetection) { EXPECT_NE(nullptr, scene); } + + +TEST_F(ut3DSImportExport, importCameraRollAnim) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/CameraRollAnim.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importCameraRollAnimWithChildObject) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/CameraRollAnimWithChildObject.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importCubesWithAlpha) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/cubes_with_alpha.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importCubeWithDiffuseTexture) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/cube_with_diffuse_texture.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importCubeWithSpecularTexture) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/cube_with_specular_texture.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importRotatingCube) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/RotatingCube.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importTargetCameraAnim) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/TargetCameraAnim.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importTest1) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/test1.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importCartWheel) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/cart_wheel.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importGranate) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/Granate.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importJeep1) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/jeep1.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importMarRifle) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/mar_rifle.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importMp5Sil) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/mp5_sil.3ds", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(ut3DSImportExport, importPyramob) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/3DS/pyramob.3DS", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} diff --git a/test/unit/utAMFImportExport.cpp b/test/unit/utAMFImportExport.cpp index 78309a105..7319320cf 100644 --- a/test/unit/utAMFImportExport.cpp +++ b/test/unit/utAMFImportExport.cpp @@ -60,6 +60,81 @@ TEST_F(utAMFImportExport, importAMFFromFileTest) { EXPECT_TRUE(importerTest()); } + +// TODO: test models-nonbsd/AMF/3_bananas.amf.7z +// requires uncompressing it in memory and we don't currently have 7z decompressor + + +TEST_F(utAMFImportExport, importTest2) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test2.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest3) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test3.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest4) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test4.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest5) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test5.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest5a) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test5a.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest6) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test6.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest7) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test7.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +#if 0 +// FIXME: these tests are disabled because they leak memory in AMFImporter_Postprocess.cpp + + +TEST_F(utAMFImportExport, importTest8) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test8.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utAMFImportExport, importTest9) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test9.amf", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +#endif // 0 + + TEST_F(utAMFImportExport, importAMFWithMatFromFileTest) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AMF/test_with_mat.amf", aiProcess_ValidateDataStructure); diff --git a/test/unit/utASEImportExport.cpp b/test/unit/utASEImportExport.cpp index 8014cbbc7..af05a2fe5 100644 --- a/test/unit/utASEImportExport.cpp +++ b/test/unit/utASEImportExport.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include using namespace Assimp; @@ -63,3 +64,112 @@ public: TEST_F(utASEImportExport, importACFromFileTest) { EXPECT_TRUE(importerTest()); } + + +TEST_F(utASEImportExport, importAnim1) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/anim.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importAnim2) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/anim2.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importCameraRollAnim) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/CameraRollAnim.ase", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importMotionCaptureROM) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/MotionCaptureROM.ase", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importRotatingCube) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/RotatingCube.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importTargetCameraAnim) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TargetCameraAnim.ase", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importTestFormatDetection) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TestFormatDetection", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importThreeCubesGreen) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/ThreeCubesGreen.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); + + ::Assimp::Importer importerLE; + const aiScene *sceneLE = importerLE.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/ThreeCubesGreen_UTF16LE.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, sceneLE); + + ::Assimp::Importer importerBE; + const aiScene *sceneBE = importerBE.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/ThreeCubesGreen_UTF16BE.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, sceneBE); + + // TODO: these scenes should probably be identical + // verify that is the case and then add tests to check it +} + + +TEST_F(utASEImportExport, importUVTransform_Normal) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TestUVTransform/UVTransform_Normal.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importUVTransform_ScaleUV1_2_OffsetUV0_0_9_Rotate_72_mirrorU) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TestUVTransform/UVTransform_ScaleUV1-2_OffsetUV0-0.9_Rotate-72_mirrorU.ase", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importUVTransform_ScaleUV2x) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TestUVTransform/UVTransform_ScaleUV2x.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utASEImportExport, importUVTransform_ScaleUV2x_Rotate45) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/ASE/TestUVTransform/UVTransform_ScaleUV2x_Rotate45.ASE", aiProcess_ValidateDataStructure); + + ASSERT_NE(nullptr, scene); +} diff --git a/test/unit/utBVHImportExport.cpp b/test/unit/utBVHImportExport.cpp index d69ac7987..5a0ff1e10 100644 --- a/test/unit/utBVHImportExport.cpp +++ b/test/unit/utBVHImportExport.cpp @@ -55,6 +55,20 @@ public: } }; -TEST_F(utBVHImportExport, importBlenFromFileTest) { +TEST_F(utBVHImportExport, import01_01) { EXPECT_TRUE(importerTest()); } + + +TEST_F(utBVHImportExport, import01_03) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BVH/01_03.bvh", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + + +TEST_F(utBVHImportExport, importBoxingToes) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BVH/Boxing_Toes.bvh", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} diff --git a/test/unit/utDXFImporterExporter.cpp b/test/unit/utDXFImporterExporter.cpp index 9193946b5..53c5328e4 100644 --- a/test/unit/utDXFImporterExporter.cpp +++ b/test/unit/utDXFImporterExporter.cpp @@ -71,3 +71,17 @@ TEST_F(utDXFImporterExporter, issue2229) { const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/DXF/issue_2229.dxf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); } + + +TEST_F(utDXFImporterExporter, importWuson) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/DXF/wuson.dxf", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utDXFImporterExporter, importRifle) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_NONBSD_DIR "/DXF/rifle.dxf", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); +}