Merge branch 'master' into MemoryOptimizationForGLTFWithSharedAttr

pull/5003/head
Kim Kulling 2023-04-03 11:28:10 +02:00 committed by GitHub
commit 19ff57a6c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
128 changed files with 1740 additions and 950 deletions

128
CODE_OF_CONDUCT.md 100644
View File

@ -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.

View File

@ -1,6 +1,8 @@
Open Asset Import Library (assimp) 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 ### ### Current project status ###
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) [![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) ![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) [![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") [![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") [![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/)
<br> <br>
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. 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 ### ### Latest Doc's ###
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
### Get involved ### ### Prebuild binaries ###
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). Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib)
<br>
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
<br>
Please check our Wiki as well: https://github.com/assimp/assimp/wiki
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb 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)<br>
#### Supported file formats #### #### Supported file formats ####
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) 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. /port Ports to other languages and scripts to maintain those.
/test Unit- and regression tests, test suite of models /test Unit- and regression tests, test suite of models
/tools Tools (old assimp viewer, command line `assimp`) /tools Tools (old assimp viewer, command line `assimp`)
/samples A small number of samples to illustrate possible /samples A small number of samples to illustrate possible use-cases for Assimp
use cases for Assimp
The source code is organized in the following way: The source code is organized in the following way:
code/Common The base implementation for importers and the infrastructure 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/PostProcessing The post-processing steps
code/AssetLib/<FormatName> Implementation for import and export for the format code/AssetLib/<FormatName> 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)<br>
### Contributing ### ### Contributing ###
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit 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. a pull request with your changes against the main repository's `master` branch.

View File

@ -815,6 +815,7 @@ nl_clean_loop:
for (; next_it != nodeArray.end(); ++next_it) { for (; next_it != nodeArray.end(); ++next_it) {
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) { 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. // 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); nodeArray.erase(nl_it);
goto nl_clean_loop; goto nl_clean_loop;

View File

@ -569,7 +569,7 @@ void Structure ::Convert<MVert>(
const FileDatabase &db) const { const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db); ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db); ReadFieldArray<ErrorPolicy_Warn>(dest.no, "no", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db); ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
//ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db); //ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db); ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);

View File

@ -640,7 +640,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
const auto zero_epsilon = ai_epsilon; const auto zero_epsilon = Math::getEpsilon<ai_real>();
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -1180,15 +1180,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto &curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto &curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
//losing channel name if using shapeGeometry->Name() //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++) { for (size_t j = 0; j < curIndices.size(); j++) {
const unsigned int curIndex = curIndices.at(j); const unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j); aiVector3D vertex = curVertices.at(j);
@ -1410,13 +1418,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto& curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto& curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto& curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
for (size_t j = 0; j < curIndices.size(); j++) { for (size_t j = 0; j < curIndices.size(); j++) {
unsigned int curIndex = curIndices.at(j); unsigned int curIndex = curIndices.at(j);

View File

@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
for (const Connection* con : conns) { for (const Connection* con : conns) {
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element); const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
if (bspc) { if (bspc) {
blendShapeChannels.push_back(bspc); auto pr = blendShapeChannels.insert(bspc);
continue; 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) { for (const Connection* con : conns) {
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element); const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
if (sg) { if (sg) {
shapeGeometries.push_back(sg); auto pr = shapeGeometries.insert(sg);
continue; if (!pr.second) {
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
}
} }
} }
} }

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_DOCUMENT_H #define INCLUDED_AI_FBX_DOCUMENT_H
#include <numeric> #include <numeric>
#include <unordered_set>
#include <stdint.h> #include <stdint.h>
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include "FBXProperties.h" #include "FBXProperties.h"
@ -855,14 +856,14 @@ public:
return fullWeights; return fullWeights;
} }
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const { const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
return shapeGeometries; return shapeGeometries;
} }
private: private:
float percent; float percent;
WeightArray fullWeights; WeightArray fullWeights;
std::vector<const ShapeGeometry*> shapeGeometries; std::unordered_set<const ShapeGeometry*> shapeGeometries;
}; };
/** DOM class for BlendShape deformers */ /** DOM class for BlendShape deformers */
@ -872,12 +873,12 @@ public:
virtual ~BlendShape(); virtual ~BlendShape();
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const { const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
return blendShapeChannels; return blendShapeChannels;
} }
private: private:
std::vector<const BlendShapeChannel*> blendShapeChannels; std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
}; };
/** DOM class for skin deformer clusters (aka sub-deformers) */ /** DOM class for skin deformer clusters (aka sub-deformers) */

View File

@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element); const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) { 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<const BlendShape*>& Geometry::GetBlendShapes() const { const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
} }

View File

@ -72,11 +72,12 @@ public:
/// @brief Get the BlendShape attached to this geometry or nullptr /// @brief Get the BlendShape attached to this geometry or nullptr
/// @return The blendshape arrays. /// @return The blendshape arrays.
const std::vector<const BlendShape*>& GetBlendShapes() const; const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
private: private:
const Skin* skin; const Skin* skin;
std::vector<const BlendShape*> blendShapes; std::unordered_set<const BlendShape*> blendShapes;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;

View File

@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() {
temp_bones_.resize(header_->numbones); 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); aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
rootnode_children_.push_back(bones_node); rootnode_children_.push_back(bones_node);
bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; // Store roots bones IDs temporarily.
std::vector<int> roots;
// Create bone matrices in local space. // Create bone matrices in local space.
for (int i = 0; i < header_->numbones; ++i) { 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]); aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
temp_bones_[i].absolute_transform = bone_node->mTransformation = 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])); aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
if (pbone[i].parent == -1) { 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 { } 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_[i].absolute_transform =
temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; 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 = temp_bones_[i].absolute_transform;
temp_bones_[i].offset_matrix.Inverse(); temp_bones_[i].offset_matrix.Inverse();
} }
// Allocate memory for each MDL root bone.
bones_node->mNumChildren = static_cast<unsigned int>(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<unsigned int>(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);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -143,6 +143,14 @@ private:
*/ */
static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); 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 */ /** Output scene to be filled */
aiScene *scene_; aiScene *scene_;
@ -198,11 +206,13 @@ private:
TempBone() : TempBone() :
node(nullptr), node(nullptr),
absolute_transform(), absolute_transform(),
offset_matrix() {} offset_matrix(),
children() {}
aiNode *node; aiNode *node;
aiMatrix4x4 absolute_transform; aiMatrix4x4 absolute_transform;
aiMatrix4x4 offset_matrix; aiMatrix4x4 offset_matrix;
std::vector<int> children; // Bone children
}; };
std::vector<TempBone> temp_bones_; std::vector<TempBone> temp_bones_;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 { namespace Assimp {
// ------------------------------------------------------------------------------------------------
CIOStreamWrapper::~CIOStreamWrapper() { CIOStreamWrapper::~CIOStreamWrapper() {
/* Various places depend on this destructor to close the file */ // Various places depend on this destructor to close the file
if (mFile) { if (mFile != nullptr) {
mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile);
} }
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
size_t CIOStreamWrapper::Read(void *pvBuffer, size_t CIOStreamWrapper::Read(void *pvBuffer,
size_t pSize, size_t pSize,
size_t pCount) { size_t pCount) {
@ -62,7 +62,7 @@ size_t CIOStreamWrapper::Read(void *pvBuffer,
return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount); return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount);
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
size_t CIOStreamWrapper::Write(const void *pvBuffer, size_t CIOStreamWrapper::Write(const void *pvBuffer,
size_t pSize, size_t pSize,
size_t pCount) { size_t pCount) {
@ -70,23 +70,23 @@ size_t CIOStreamWrapper::Write(const void *pvBuffer,
return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount); return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount);
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
aiReturn CIOStreamWrapper::Seek(size_t pOffset, aiReturn CIOStreamWrapper::Seek(size_t pOffset,
aiOrigin pOrigin) { aiOrigin pOrigin) {
return mFile->SeekProc(mFile, pOffset, pOrigin); return mFile->SeekProc(mFile, pOffset, pOrigin);
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
size_t CIOStreamWrapper::Tell() const { size_t CIOStreamWrapper::Tell() const {
return mFile->TellProc(mFile); return mFile->TellProc(mFile);
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
size_t CIOStreamWrapper::FileSize() const { size_t CIOStreamWrapper::FileSize() const {
return mFile->FileSizeProc(mFile); return mFile->FileSizeProc(mFile);
} }
// ................................................................... // ------------------------------------------------------------------------------------------------
void CIOStreamWrapper::Flush() { void CIOStreamWrapper::Flush() {
return mFile->FlushProc(mFile); return mFile->FlushProc(mFile);
} }

View File

@ -47,48 +47,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/cfileio.h> #include <assimp/cfileio.h>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/ai_assert.h>
namespace Assimp { namespace Assimp {
class CIOSystemWrapper; class CIOSystemWrapper;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API /// @brief Custom IOStream implementation for the C-API-
class CIOStreamWrapper : public IOStream { // ------------------------------------------------------------------------------------------------
class CIOStreamWrapper final : public IOStream {
public: public:
explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) : explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io);
mFile(pFile), ~CIOStreamWrapper() override;
mIO(io) {} size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override;
~CIOStreamWrapper(void); size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override;
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
size_t Read(void *pvBuffer, size_t pSize, size_t pCount); size_t Tell(void) const override;
size_t Write(const void *pvBuffer, size_t pSize, size_t pCount); size_t FileSize() const override;
aiReturn Seek(size_t pOffset, aiOrigin pOrigin); void Flush() override;
size_t Tell(void) const;
size_t FileSize() const;
void Flush();
private: private:
aiFile *mFile; aiFile *mFile;
CIOSystemWrapper *mIO; 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; friend class CIOStreamWrapper;
public: public:
explicit CIOSystemWrapper(aiFileIO *pFile) : explicit CIOSystemWrapper(aiFileIO *pFile);
mFileSystem(pFile) {} ~CIOSystemWrapper() override = default;
bool Exists(const char *pFile) const override;
bool Exists(const char *pFile) const; char getOsSeparator() const override;
char getOsSeparator() const; IOStream *Open(const char *pFile, const char *pMode = "rb") override;
IOStream *Open(const char *pFile, const char *pMode = "rb"); void Close(IOStream *pFile) override;
void Close(IOStream *pFile);
private: private:
aiFileIO *mFileSystem; aiFileIO *mFileSystem;
}; };
inline CIOSystemWrapper::CIOSystemWrapper(aiFileIO *pFile) : mFileSystem(pFile) {
ai_assert(pFile != nullptr);
}
} // namespace Assimp } // namespace Assimp
#endif #endif // AI_CIOSYSTEM_H_INCLUDED

View File

@ -218,6 +218,12 @@ SET( CApi_SRCS
) )
SOURCE_GROUP(CApi FILES ${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 SET( STEPParser_SRCS
AssetLib/STEPParser/STEPFileReader.h AssetLib/STEPParser/STEPFileReader.h
AssetLib/STEPParser/STEPFileReader.cpp AssetLib/STEPParser/STEPFileReader.cpp
@ -1129,6 +1135,7 @@ SET( assimp_src
${Core_SRCS} ${Core_SRCS}
${CApi_SRCS} ${CApi_SRCS}
${Common_SRCS} ${Common_SRCS}
${Geometry_SRCS}
${Logging_SRCS} ${Logging_SRCS}
${Exporter_SRCS} ${Exporter_SRCS}
${PostProcessing_SRCS} ${PostProcessing_SRCS}
@ -1188,7 +1195,70 @@ TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
IF (ASSIMP_WARNINGS_AS_ERRORS) IF (ASSIMP_WARNINGS_AS_ERRORS)
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)") MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
IF (MSVC) IF (MSVC)
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) TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX)
ENDIF()
ELSE() ELSE()
TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror) TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror)
ENDIF() ENDIF()

View File

@ -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.*/ * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T> template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) { inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) {
// Point in triangle test using baryzentric coordinates // pp should be left side of the three triangle side, by ccw arrow
const aiVector2D v0 = p1 - p0; return OnLeftSideOfLine2D(p0, p1, pp) && OnLeftSideOfLine2D(p1, p2, pp) && OnLeftSideOfLine2D(p2, p0, pp);
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);
} }

View File

@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map> #include <unordered_map>
using namespace Assimp; using namespace Assimp;
void mydummy() {} void mydummy() {}
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -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 <assimp/vector3.h>
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

View File

@ -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 <assimp/types.h>
#include <assimp/mesh.h>
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

View File

@ -60,10 +60,6 @@ CalcTangentsProcess::CalcTangentsProcess() :
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
CalcTangentsProcess::~CalcTangentsProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool CalcTangentsProcess::IsActive(unsigned int pFlags) const { bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {

View File

@ -59,14 +59,11 @@ namespace Assimp
* because the joining of vertices also considers tangents and bitangents for * because the joining of vertices also considers tangents and bitangents for
* uniqueness. * uniqueness.
*/ */
class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess {
{
public: public:
CalcTangentsProcess(); CalcTangentsProcess();
~CalcTangentsProcess(); ~CalcTangentsProcess() override = default;
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag. /** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. * @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, * @return true if the process is present in this flag fields,
* false if not. * false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
// setter for configMaxAngle // setter for configMaxAngle
inline void SetMaxSmoothAngle(float f) void SetMaxSmoothAngle(float f) {
{
configMaxAngle =f; configMaxAngle =f;
} }
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Calculates tangents and bitangents for a specific mesh. /** Calculates tangents and bitangents for a specific mesh.
* @param pMesh The mesh to process. * @param pMesh The mesh to process.
@ -103,10 +97,9 @@ protected:
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
private: private:
/** Configuration option: maximum smoothing angle, in radians*/ /** Configuration option: maximum smoothing angle, in radians*/
float configMaxAngle; float configMaxAngle;
unsigned int configSourceUV; unsigned int configSourceUV;

View File

@ -57,14 +57,6 @@ namespace {
const static ai_real angle_epsilon = ai_real( 0.95 ); 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. // Returns whether the processing step is present in the given flag field.
bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const

View File

@ -59,13 +59,10 @@ namespace Assimp {
/** ComputeUVMappingProcess - converts special mappings, such as spherical, /** ComputeUVMappingProcess - converts special mappings, such as spherical,
* cylindrical or boxed to proper UV coordinates for rendering. * cylindrical or boxed to proper UV coordinates for rendering.
*/ */
class ComputeUVMappingProcess : public BaseProcess class ComputeUVMappingProcess : public BaseProcess {
{
public:
ComputeUVMappingProcess();
~ComputeUVMappingProcess();
public: public:
ComputeUVMappingProcess() = default;
~ComputeUVMappingProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
@ -73,14 +70,14 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
protected: protected:
@ -125,8 +122,7 @@ protected:
private: private:
// temporary structure to describe a mapping // temporary structure to describe a mapping
struct MappingInfo struct MappingInfo {
{
explicit MappingInfo(aiTextureMapping _type) explicit MappingInfo(aiTextureMapping _type)
: type (_type) : type (_type)
, axis (0.f,1.f,0.f) , axis (0.f,1.f,0.f)
@ -137,8 +133,7 @@ private:
aiVector3D axis; aiVector3D axis;
unsigned int uv; unsigned int uv;
bool operator== (const MappingInfo& other) bool operator== (const MappingInfo& other) {
{
return type == other.type && axis == other.axis; return type == other.type && axis == other.axis;
} }
}; };

View File

@ -79,14 +79,6 @@ void flipUVs(aiMeshType *pMesh) {
} // namespace } // 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. // Returns whether the processing step is present in the given flag field.
bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const { bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
@ -305,14 +297,6 @@ void FlipUVsProcess::ProcessMesh(aiMesh *pMesh) {
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS #ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
// # FlipWindingOrderProcess // # 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. // Returns whether the processing step is present in the given flag field.
bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const { bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 * @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: public:
MakeLeftHandedProcess(); MakeLeftHandedProcess() = default;
~MakeLeftHandedProcess(); ~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: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Recursively converts a node and all of its children /** 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 /** Postprocessing step to flip the face order of the imported data
*/ */
class FlipWindingOrderProcess : public BaseProcess class FlipWindingOrderProcess : public BaseProcess {
{
friend class Importer; friend class Importer;
public: public:
/** Constructor to be privately used by Importer */ /** Constructor to be privately used by Importer */
FlipWindingOrderProcess(); FlipWindingOrderProcess() = default;
/** Destructor, private as well */ /** 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 */ /** Some other types of post-processing require winding order flips */
static void ProcessMesh( aiMesh* pMesh); static void ProcessMesh( aiMesh* pMesh);
}; };

View File

@ -43,42 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/// @file DeboneProcess.cpp /// @file DeboneProcess.cpp
/** Implementation of the DeboneProcess post processing step */ /** Implementation of the DeboneProcess post processing step */
// internal headers of the post-processing framework // internal headers of the post-processing framework
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include "DeboneProcess.h" #include "DeboneProcess.h"
#include <stdio.h> #include <stdio.h>
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
DeboneProcess::DeboneProcess() DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {}
{
mNumBones = 0;
mNumBonesCanDoWithout = 0;
mThreshold = AI_DEBONE_THRESHOLD;
mAllOrNone = false;
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
DeboneProcess::~DeboneProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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; return (pFlags & aiProcess_Debone) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // 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 // get the current value of the property
mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false; mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD); 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. // 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"); ASSIMP_LOG_DEBUG("DeboneProcess begin");
if(!pScene->mNumMeshes) { if(!pScene->mNumMeshes) {
@ -117,10 +100,8 @@ void DeboneProcess::Execute( aiScene* pScene)
// build a new array of meshes for the scene // build a new array of meshes for the scene
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
for(unsigned int a=0;a<pScene->mNumMeshes;a++) for (unsigned int a=0;a<pScene->mNumMeshes; ++a) {
{
aiMesh* srcMesh = pScene->mMeshes[a]; aiMesh* srcMesh = pScene->mMeshes[a];
std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes; std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
if(splitList[a]) { 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 // and destroy the source mesh. It should be completely contained inside the new submeshes
delete srcMesh; delete srcMesh;
} } else {
else {
// Mesh is kept unchanged - store it's new place in the mesh array // Mesh is kept unchanged - store it's new place in the mesh array
mSubMeshIndices[a].emplace_back(static_cast<unsigned int>(meshes.size()), (aiNode *)nullptr); mSubMeshIndices[a].emplace_back(static_cast<unsigned int>(meshes.size()), (aiNode *)nullptr);
meshes.push_back(srcMesh); meshes.push_back(srcMesh);
@ -173,8 +153,7 @@ void DeboneProcess::Execute( aiScene* pScene)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Counts bones total/removable in a given mesh. // Counts bones total/removable in a given mesh.
bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) {
{
if(!pMesh->HasBones()) { if(!pMesh->HasBones()) {
return false; return false;
} }
@ -193,25 +172,23 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
for(unsigned int i=0;i<pMesh->mNumBones;i++) { for(unsigned int i=0;i<pMesh->mNumBones;i++) {
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) { for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
float w = pMesh->mBones[i]->mWeights[j].mWeight; float w = pMesh->mBones[i]->mWeights[j].mWeight;
if (w == 0.0f) {
if(w==0.0f) {
continue; continue;
} }
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
if(w>=mThreshold) { if (w >= mThreshold) {
if (vertexBones[vid] != cUnowned) {
if(vertexBones[vid]!=cUnowned) { //double entry
if(vertexBones[vid]==i) //double entry if(vertexBones[vid]==i) {
{
ASSIMP_LOG_WARN("Encountered double entry in bone weights"); ASSIMP_LOG_WARN("Encountered double entry in bone weights");
} } else {
else //TODO: track attraction in order to break tie //TODO: track attraction in order to break tie
{
vertexBones[vid] = cCoowned; vertexBones[vid] = cCoowned;
} }
} else {
vertexBones[vid] = i;
} }
else vertexBones[vid] = i;
} }
if(!isBoneNecessary[i]) { if(!isBoneNecessary[i]) {
@ -227,13 +204,16 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
if(isInterstitialRequired) { if(isInterstitialRequired) {
for(unsigned int i=0;i<pMesh->mNumFaces;i++) { for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
for (unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
if(v!=w) { if (v != w) {
if(v<pMesh->mNumBones) isBoneNecessary[v] = true; if(v<pMesh->mNumBones) {
if(w<pMesh->mNumBones) isBoneNecessary[w] = true; isBoneNecessary[v] = true;
}
if (w<pMesh->mNumBones) {
isBoneNecessary[w] = true;
}
} }
} }
} }
@ -252,8 +232,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Splits the given mesh by bone count. // 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 // same deal here as ConsiderMesh basically
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false); std::vector<bool> 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 // 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 // rebuild the node's mesh index list
std::vector<unsigned int> newMeshList; std::vector<unsigned int> newMeshList;
@ -430,8 +408,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply the node transformation to a mesh // 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 // Check whether we need to transform the coordinates at all
if (!mat.IsIdentity()) { if (!mat.IsIdentity()) {

View File

@ -70,7 +70,7 @@ namespace Assimp {
class DeboneProcess : public BaseProcess { class DeboneProcess : public BaseProcess {
public: public:
DeboneProcess(); DeboneProcess();
~DeboneProcess(); ~DeboneProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag. /** 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, * @return true if the process is present in this flag fields,
* false if not. * false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -94,7 +94,7 @@ protected:
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @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. /** Counts bones total/removable in a given mesh.

View File

@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; 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. // Returns whether the processing step is present in the given flag field.
bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const {

View File

@ -55,8 +55,8 @@ namespace Assimp {
*/ */
class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess {
public: public:
DropFaceNormalsProcess(); DropFaceNormalsProcess() = default;
~DropFaceNormalsProcess(); ~DropFaceNormalsProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
@ -64,15 +64,14 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
private: private:
bool DropMeshFaceNormals(aiMesh* pcMesh); bool DropMeshFaceNormals(aiMesh* pcMesh);

View File

@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
EmbedTexturesProcess::EmbedTexturesProcess() = default;
EmbedTexturesProcess::~EmbedTexturesProcess() = default;
bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_EmbedTextures) != 0; return (pFlags & aiProcess_EmbedTextures) != 0;
} }

View File

@ -62,19 +62,19 @@ namespace Assimp {
class ASSIMP_API EmbedTexturesProcess : public BaseProcess { class ASSIMP_API EmbedTexturesProcess : public BaseProcess {
public: public:
/// The default class constructor. /// The default class constructor.
EmbedTexturesProcess(); EmbedTexturesProcess() = default;
/// The class destructor. /// The class destructor.
virtual ~EmbedTexturesProcess(); ~EmbedTexturesProcess() override = default;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual bool IsActive(unsigned int pFlags) const; bool IsActive(unsigned int pFlags) const override;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual void Execute(aiScene* pScene); virtual void Execute(aiScene* pScene) override;
private: private:
// Resolve the path and add the file content to the scene as a texture. // Resolve the path and add the file content to the scene as a texture.

View File

@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include "FindDegenerates.h" #include "FindDegenerates.h"
#include "Geometry/GeometryUtils.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -63,10 +64,6 @@ FindDegeneratesProcess::FindDegeneratesProcess() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FindDegeneratesProcess::~FindDegeneratesProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
@ -132,37 +129,6 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
} }
} }
static ai_real 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;
}
static ai_real 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;
}
static ai_real 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;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported mesh // Executes the post processing step on the given imported mesh
bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
@ -218,7 +184,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
if ( mConfigCheckAreaOfTriangle ) { if ( mConfigCheckAreaOfTriangle ) {
if ( face.mNumIndices == 3 ) { if ( face.mNumIndices == 3 ) {
ai_real area = calculateAreaOfTriangle( face, mesh ); ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh );
if (area < ai_epsilon) { if (area < ai_epsilon) {
if ( mConfigRemoveDegenerates ) { if ( mConfigRemoveDegenerates ) {
remove_me[ a ] = true; remove_me[ a ] = true;

View File

@ -59,19 +59,19 @@ namespace Assimp {
class ASSIMP_API FindDegeneratesProcess : public BaseProcess { class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
public: public:
FindDegeneratesProcess(); FindDegeneratesProcess();
~FindDegeneratesProcess(); ~FindDegeneratesProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether step is active // Check whether step is active
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Execute step on a given scene // Execute step on a given scene
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setup import settings // Setup import settings
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Execute step on a given mesh // Execute step on a given mesh
@ -105,23 +105,19 @@ private:
bool mConfigCheckAreaOfTriangle; bool mConfigCheckAreaOfTriangle;
}; };
inline inline void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
mConfigRemoveDegenerates = enabled; mConfigRemoveDegenerates = enabled;
} }
inline inline bool FindDegeneratesProcess::IsInstantRemoval() const {
bool FindDegeneratesProcess::IsInstantRemoval() const {
return mConfigRemoveDegenerates; return mConfigRemoveDegenerates;
} }
inline inline void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
mConfigCheckAreaOfTriangle = enabled; mConfigCheckAreaOfTriangle = enabled;
} }
inline inline bool FindDegeneratesProcess::isAreaCheckEnabled() const {
bool FindDegeneratesProcess::isAreaCheckEnabled() const {
return mConfigCheckAreaOfTriangle; return mConfigCheckAreaOfTriangle;
} }

View File

@ -58,10 +58,6 @@ FindInstancesProcess::FindInstancesProcess()
: configSpeedFlag (false) : configSpeedFlag (false)
{} {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FindInstancesProcess::~FindInstancesProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool FindInstancesProcess::IsActive( unsigned int pFlags) const bool FindInstancesProcess::IsActive( unsigned int pFlags) const

View File

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
class FindInstancesProcessTest; class FindInstancesProcessTest;
namespace Assimp { namespace Assimp {
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -60,8 +61,7 @@ namespace Assimp {
* @param in Input mesh * @param in Input mesh
* @return Hash. * @return Hash.
*/ */
inline inline uint64_t GetMeshHash(aiMesh* in) {
uint64_t GetMeshHash(aiMesh* in) {
ai_assert(nullptr != in); ai_assert(nullptr != in);
// ... get an unique value representing the vertex format of the mesh // ... get an unique value representing the vertex format of the mesh
@ -83,8 +83,7 @@ uint64_t GetMeshHash(aiMesh* in) {
* @param e Epsilon * @param e Epsilon
* @return true if the arrays are identical * @return true if the arrays are identical
*/ */
inline inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
unsigned int size, float e) { unsigned int size, float e) {
for (const aiVector3D* end = first+size; first != end; ++first,++second) { for (const aiVector3D* end = first+size; first != end; ++first,++second) {
if ( (*first - *second).SquareLength() >= e) 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 /** @brief A post-processing steps to search for instanced meshes
*/ */
class FindInstancesProcess : public BaseProcess class FindInstancesProcess : public BaseProcess {
{
public: public:
FindInstancesProcess(); FindInstancesProcess();
~FindInstancesProcess(); ~FindInstancesProcess() override = default;
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether step is active in given flags combination // 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 // Execute step on a given scene
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setup properties prior to executing the process // Setup properties prior to executing the process
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
private: private:
bool configSpeedFlag; bool configSpeedFlag;
}; // ! end class FindInstancesProcess }; // ! end class FindInstancesProcess
} // ! end namespace Assimp } // ! end namespace Assimp
#endif // !! AI_FINDINSTANCES_H_INC #endif // !! AI_FINDINSTANCES_H_INC

View File

@ -60,10 +60,6 @@ FindInvalidDataProcess::FindInvalidDataProcess() :
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FindInvalidDataProcess::~FindInvalidDataProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const { bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {

View File

@ -64,35 +64,37 @@ namespace Assimp {
* which have zero normal vectors. */ * which have zero normal vectors. */
class ASSIMP_API FindInvalidDataProcess : public BaseProcess { class ASSIMP_API FindInvalidDataProcess : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
FindInvalidDataProcess(); FindInvalidDataProcess();
~FindInvalidDataProcess(); ~FindInvalidDataProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// /// Returns active state.
bool IsActive(unsigned int pFlags) const; bool IsActive(unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setup import settings /// Setup import settings
void SetupProperties(const Importer *pImp); void SetupProperties(const Importer *pImp) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Run the step /// Run the step
void Execute(aiScene *pScene); void Execute(aiScene *pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post-processing step on the given mesh /// Executes the post-processing step on the given mesh
* @param pMesh The mesh to process. /// @param pMesh The mesh to process.
* @return 0 - nothing, 1 - removed sth, 2 - please delete me */ /// @return 0 - nothing, 1 - removed sth, 2 - please delete me */
int ProcessMesh(aiMesh *pMesh); int ProcessMesh(aiMesh *pMesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post-processing step on the given animation /// Executes the post-processing step on the given animation
* @param anim The animation to process. */ /// @param anim The animation to process. */
void ProcessAnimation(aiAnimation *anim); void ProcessAnimation(aiAnimation *anim);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post-processing step on the given anim channel /// Executes the post-processing step on the given anim channel
* @param anim The animation channel to process.*/ /// @param anim The animation channel to process.*/
void ProcessAnimationChannel(aiNodeAnim *anim); void ProcessAnimationChannel(aiNodeAnim *anim);
private: private:

View File

@ -56,26 +56,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; 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. // 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; return (pFlags & aiProcess_FixInfacingNormals) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // 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"); ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin");
bool bHas( false ); bool bHas( false );

View File

@ -49,8 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiMesh; struct aiMesh;
namespace Assimp namespace Assimp {
{
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The FixInfacingNormalsProcess tries to determine whether the normal /** The FixInfacingNormalsProcess tries to determine whether the normal
@ -59,8 +58,10 @@ namespace Assimp
*/ */
class FixInfacingNormalsProcess : public BaseProcess { class FixInfacingNormalsProcess : public BaseProcess {
public: 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. /** Returns whether the processing step is present in the given flag field.
@ -68,14 +69,14 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
protected: protected:

View File

@ -48,10 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
GenBoundingBoxesProcess::GenBoundingBoxesProcess() = default;
GenBoundingBoxesProcess::~GenBoundingBoxesProcess() = default;
bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const { bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const {
return 0 != ( pFlags & aiProcess_GenBoundingBoxes ); return 0 != ( pFlags & aiProcess_GenBoundingBoxes );
} }

View File

@ -19,7 +19,7 @@ conditions are met:
copyright notice, this list of conditions and the copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other following disclaimer in the documentation and/or other
materials provided with the distribution. materials provided with the distribution.
s
* Neither the name of the assimp team, nor the names of its * Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products contributors may be used to endorse or promote products
derived from this software without specific prior 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 { 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 { class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess {
public: public:
/// The class constructor. // -------------------------------------------------------------------
GenBoundingBoxesProcess(); /// The default class constructor / destructor.
/// The class destructor. GenBoundingBoxesProcess() = default;
~GenBoundingBoxesProcess(); ~GenBoundingBoxesProcess() override = default;
/// Will return true, if aiProcess_GenBoundingBoxes is defined.
// -------------------------------------------------------------------
/// @brief Will return true, if aiProcess_GenBoundingBoxes is defined.
bool IsActive(unsigned int pFlags) const override; bool IsActive(unsigned int pFlags) const override;
/// The execution callback.
// -------------------------------------------------------------------
/// @brief The execution callback.
void Execute(aiScene* pScene) override; void Execute(aiScene* pScene) override;
}; };

View File

@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; 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. // Returns whether the processing step is present in the given flag field.
bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const { bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {

View File

@ -47,35 +47,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Common/BaseProcess.h" #include "Common/BaseProcess.h"
#include <assimp/mesh.h> #include <assimp/mesh.h>
namespace Assimp namespace Assimp {
{
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The GenFaceNormalsProcess computes face normals for all faces of all meshes /**
*/ * @brief The GenFaceNormalsProcess computes face normals for all faces of all meshes
class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess */
{ class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess {
public: 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. /** Returns whether the processing step is present in the given flag field.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with. A bitwise
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
private: private:
bool GenMeshFaceNormals(aiMesh* pcMesh); bool GenMeshFaceNormals(aiMesh* pcMesh);

View File

@ -60,10 +60,6 @@ GenVertexNormalsProcess::GenVertexNormalsProcess() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
GenVertexNormalsProcess::~GenVertexNormalsProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const { bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
@ -109,11 +105,11 @@ void GenVertexNormalsProcess::Execute(aiScene *pScene) {
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) { bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
if (nullptr != pMesh->mNormals) { if (nullptr != pMesh->mNormals) {
if (force_) if (!force_) {
delete[] pMesh->mNormals;
else
return false; return false;
} }
delete[] pMesh->mNormals;
}
// If the mesh consists of lines and/or points but not of // If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors // triangles or higher-order polygons the normal vectors
@ -144,8 +140,9 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int m
const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]]; 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 // 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 // changed and the cross product to calculate the normal needs to be reversed
if (flippedWindingOrder_ != leftHanded_) if (flippedWindingOrder_ != leftHanded_) {
std::swap(pV2, pV3); std::swap(pV2, pV3);
}
const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
for (unsigned int i = 0; i < face.mNumIndices; ++i) { for (unsigned int i = 0; i < face.mNumIndices; ++i) {

View File

@ -60,8 +60,10 @@ namespace Assimp {
*/ */
class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { class ASSIMP_API GenVertexNormalsProcess : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
GenVertexNormalsProcess(); GenVertexNormalsProcess();
~GenVertexNormalsProcess(); ~GenVertexNormalsProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag. /** 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, * @return true if the process is present in this flag fields,
* false if not. * false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * 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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// setter for configMaxAngle // setter for configMaxAngle
inline void SetMaxSmoothAngle(ai_real f) { inline void SetMaxSmoothAngle(ai_real f) {

View File

@ -68,10 +68,6 @@ ImproveCacheLocalityProcess::ImproveCacheLocalityProcess()
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const { bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const {

View File

@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiMesh; struct aiMesh;
namespace Assimp namespace Assimp {
{
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The ImproveCacheLocalityProcess reorders all faces for improved vertex /** The ImproveCacheLocalityProcess reorders all faces for improved vertex
@ -61,26 +60,24 @@ namespace Assimp
* *
* @note This step expects triagulated input data. * @note This step expects triagulated input data.
*/ */
class ImproveCacheLocalityProcess : public BaseProcess class ImproveCacheLocalityProcess : public BaseProcess {
{
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
ImproveCacheLocalityProcess(); ImproveCacheLocalityProcess();
~ImproveCacheLocalityProcess(); ~ImproveCacheLocalityProcess() override = default;
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether the pp step is active // 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 // Executes the pp step on a given scene
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Configures the pp step // Configures the pp step
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------

View File

@ -51,8 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiMesh; struct aiMesh;
namespace Assimp namespace Assimp {
{
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The JoinVerticesProcess unites identical vertices in all imported meshes. /** The JoinVerticesProcess unites identical vertices in all imported meshes.
@ -65,12 +64,9 @@ namespace Assimp
class ASSIMP_API JoinVerticesProcess : public BaseProcess { class ASSIMP_API JoinVerticesProcess : public BaseProcess {
public: public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/// @brief The default class constructor. /// The default class constructor / destructor.
JoinVerticesProcess() = default; JoinVerticesProcess() = default;
~JoinVerticesProcess() override = default;
// -------------------------------------------------------------------
/// @brief The default class destructor.
~JoinVerticesProcess() = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
@ -78,14 +74,14 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Unites identical vertices in the given mesh. /** Unites identical vertices in the given mesh.

View File

@ -53,11 +53,9 @@ namespace Assimp {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {} LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {
// empty
// ------------------------------------------------------------------------------------------------ }
// Destructor, private as well
LimitBoneWeightsProcess::~LimitBoneWeightsProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.

View File

@ -74,8 +74,10 @@ namespace Assimp {
*/ */
class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess { class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
LimitBoneWeightsProcess(); LimitBoneWeightsProcess();
~LimitBoneWeightsProcess(); ~LimitBoneWeightsProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag. /** 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, * @return true if the process is present in this flag fields,
* false if not. * false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
// -------------------------------------------------------------------
/** Limits the bone weight count for all vertices in the given mesh.
* @param pMesh The mesh to process.
*/
void ProcessMesh( aiMesh* pMesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @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 */ /** Describes a bone weight on a vertex */

View File

@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------
MakeVerboseFormatProcess::MakeVerboseFormatProcess() = default;
// ------------------------------------------------------------------------------------------------
MakeVerboseFormatProcess::~MakeVerboseFormatProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void MakeVerboseFormatProcess::Execute(aiScene *pScene) { void MakeVerboseFormatProcess::Execute(aiScene *pScene) {

View File

@ -66,22 +66,19 @@ namespace Assimp {
* The step has been added because it was required by the viewer, however * 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 * it has been moved to the main library since others might find it
* useful, too. */ * useful, too. */
class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess {
{
public:
MakeVerboseFormatProcess();
~MakeVerboseFormatProcess();
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
MakeVerboseFormatProcess() = default;
~MakeVerboseFormatProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with. A bitwise
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not */ * @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 // NOTE: There is no direct flag that corresponds to
// this postprocess step. // this postprocess step.
@ -92,7 +89,7 @@ public:
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. */ * @param pScene The imported data to work at. */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
public: public:

View File

@ -78,10 +78,6 @@ OptimizeGraphProcess::OptimizeGraphProcess() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
OptimizeGraphProcess::~OptimizeGraphProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const { bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {

View File

@ -71,8 +71,10 @@ namespace Assimp {
*/ */
class OptimizeGraphProcess : public BaseProcess { class OptimizeGraphProcess : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
OptimizeGraphProcess(); OptimizeGraphProcess();
~OptimizeGraphProcess(); ~OptimizeGraphProcess() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const override; bool IsActive( unsigned int pFlags) const override;

View File

@ -69,10 +69,6 @@ OptimizeMeshesProcess::OptimizeMeshesProcess()
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
OptimizeMeshesProcess::~OptimizeMeshesProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const

View File

@ -68,11 +68,10 @@ namespace Assimp {
*/ */
class OptimizeMeshesProcess : public BaseProcess { class OptimizeMeshesProcess : public BaseProcess {
public: public:
/// @brief The class constructor. // -------------------------------------------------------------------
/// The default class constructor / destructor.
OptimizeMeshesProcess(); OptimizeMeshesProcess();
~OptimizeMeshesProcess() override = default;
/// @brief The class destructor.
~OptimizeMeshesProcess();
/** @brief Internal utility to store additional mesh info /** @brief Internal utility to store additional mesh info
*/ */
@ -94,16 +93,14 @@ public:
unsigned int output_id; 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 /** @brief Specify whether you want meshes with different

View File

@ -68,10 +68,6 @@ PretransformVertices::PretransformVertices() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
PretransformVertices::~PretransformVertices() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool PretransformVertices::IsActive(unsigned int pFlags) const { bool PretransformVertices::IsActive(unsigned int pFlags) const {

View File

@ -68,8 +68,10 @@ namespace Assimp {
*/ */
class ASSIMP_API PretransformVertices : public BaseProcess { class ASSIMP_API PretransformVertices : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
PretransformVertices(); PretransformVertices();
~PretransformVertices(); ~PretransformVertices() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether step is active // Check whether step is active

View File

@ -62,10 +62,6 @@ RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const

View File

@ -59,23 +59,22 @@ namespace Assimp {
*/ */
class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess {
public: public:
/// The default class constructor. // -------------------------------------------------------------------
/// The default class constructor / destructor.
RemoveRedundantMatsProcess(); RemoveRedundantMatsProcess();
~RemoveRedundantMatsProcess() override = default;
/// The class destructor.
~RemoveRedundantMatsProcess();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether step is active // Check whether step is active
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Execute step on a given scene // Execute step on a given scene
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setup import settings // Setup import settings
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Set list of fixed (inmutable) materials /** @brief Set list of fixed (inmutable) materials

View File

@ -56,10 +56,6 @@ using namespace Assimp;
RemoveVCProcess::RemoveVCProcess() : RemoveVCProcess::RemoveVCProcess() :
configDeleteFlags(), mScene() {} configDeleteFlags(), mScene() {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
RemoveVCProcess::~RemoveVCProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool RemoveVCProcess::IsActive(unsigned int pFlags) const { bool RemoveVCProcess::IsActive(unsigned int pFlags) const {

View File

@ -58,11 +58,10 @@ namespace Assimp {
*/ */
class ASSIMP_API RemoveVCProcess : public BaseProcess { class ASSIMP_API RemoveVCProcess : public BaseProcess {
public: public:
/// The default class constructor. // -------------------------------------------------------------------
/// The default class constructor / destructor.
RemoveVCProcess(); RemoveVCProcess();
~RemoveVCProcess() override = default;
/// The class destructor.
~RemoveVCProcess();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
@ -70,37 +69,35 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * 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 /** Manually setup the configuration flags for the step
* *
* @param Bitwise combination of the #aiComponent enumerated values. * @param Bitwise combination of the #aiComponent enumerated values.
*/ */
void SetDeleteFlags(unsigned int f) void SetDeleteFlags(unsigned int f) {
{
configDeleteFlags = f; configDeleteFlags = f;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Query the current configuration. /** Query the current configuration.
*/ */
unsigned int GetDeleteFlags() const unsigned int GetDeleteFlags() const {
{
return configDeleteFlags; return configDeleteFlags;
} }

View File

@ -47,25 +47,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
ScaleProcess::ScaleProcess() // ------------------------------------------------------------------------------------------------
: BaseProcess() ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { // empty
} }
ScaleProcess::~ScaleProcess() = default; // ------------------------------------------------------------------------------------------------
void ScaleProcess::setScale( ai_real scale ) { void ScaleProcess::setScale( ai_real scale ) {
mScale = scale; mScale = scale;
} }
// ------------------------------------------------------------------------------------------------
ai_real ScaleProcess::getScale() const { ai_real ScaleProcess::getScale() const {
return mScale; return mScale;
} }
// ------------------------------------------------------------------------------------------------
bool ScaleProcess::IsActive( unsigned int pFlags ) const { bool ScaleProcess::IsActive( unsigned int pFlags ) const {
return ( pFlags & aiProcess_GlobalScale ) != 0; return ( pFlags & aiProcess_GlobalScale ) != 0;
} }
// ------------------------------------------------------------------------------------------------
void ScaleProcess::SetupProperties( const Importer* pImp ) { void ScaleProcess::SetupProperties( const Importer* pImp ) {
// User scaling // User scaling
mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f );
@ -78,6 +80,7 @@ void ScaleProcess::SetupProperties( const Importer* pImp ) {
mScale *= importerScale; mScale *= importerScale;
} }
// ------------------------------------------------------------------------------------------------
void ScaleProcess::Execute( aiScene* pScene ) { void ScaleProcess::Execute( aiScene* pScene ) {
if(mScale == 1.0f) { if(mScale == 1.0f) {
return; // nothing to scale return; // nothing to scale
@ -96,37 +99,30 @@ void ScaleProcess::Execute( aiScene* pScene ) {
} }
// Process animations and update position transform to new unit system // 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]; 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]; 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]; aiVectorKey& vectorKey = anim->mPositionKeys[posKey];
vectorKey.mValue *= mScale; 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]; aiMesh *mesh = pScene->mMeshes[meshID];
// Reconstruct mesh vertices to the new unit system // 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]; aiVector3D& vertex = mesh->mVertices[vertexID];
vertex *= mScale; vertex *= mScale;
} }
// bone placement / scaling // 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 // Reconstruct matrix by transform rather than by scale
// This prevent scale values being changed which can // This prevent scale values being changed which can
// be meaningful in some cases // be meaningful in some cases
@ -152,12 +148,10 @@ void ScaleProcess::Execute( aiScene* pScene ) {
// animation mesh processing // animation mesh processing
// convert by position rather than scale. // 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]; 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]; aiVector3D& vertex = animMesh->mVertices[vertexID];
vertex *= mScale; vertex *= mScale;
} }
@ -167,16 +161,17 @@ void ScaleProcess::Execute( aiScene* pScene ) {
traverseNodes( pScene->mRootNode ); traverseNodes( pScene->mRootNode );
} }
// ------------------------------------------------------------------------------------------------
void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
applyScaling( node ); 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! // recurse into the tree until we are done!
traverseNodes( node->mChildren[i], nested_node_id+1 ); traverseNodes( node->mChildren[i], nested_node_id+1 );
} }
} }
// ------------------------------------------------------------------------------------------------
void ScaleProcess::applyScaling( aiNode *currentNode ) { void ScaleProcess::applyScaling( aiNode *currentNode ) {
if ( nullptr != currentNode ) { if ( nullptr != currentNode ) {
// Reconstruct matrix by transform rather than by scale // Reconstruct matrix by transform rather than by scale

View File

@ -62,11 +62,10 @@ namespace Assimp {
*/ */
class ASSIMP_API ScaleProcess : public BaseProcess { class ASSIMP_API ScaleProcess : public BaseProcess {
public: public:
/// The default class constructor. // -------------------------------------------------------------------
/// The default class constructor / destructor.
ScaleProcess(); ScaleProcess();
~ScaleProcess() override = default;
/// The class destructor.
virtual ~ScaleProcess();
/// Will set the scale manually. /// Will set the scale manually.
void setScale( ai_real scale ); void setScale( ai_real scale );
@ -75,13 +74,13 @@ public:
ai_real getScale() const; ai_real getScale() const;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual bool IsActive( unsigned int pFlags ) const; virtual bool IsActive( unsigned int pFlags ) const override;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual void SetupProperties( const Importer* pImp ); virtual void SetupProperties( const Importer* pImp ) override;
/// Overwritten, @see BaseProcess /// Overwritten, @see BaseProcess
virtual void Execute( aiScene* pScene ); virtual void Execute( aiScene* pScene ) override;
private: private:
void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 );

View File

@ -59,10 +59,6 @@ SortByPTypeProcess::SortByPTypeProcess() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
SortByPTypeProcess::~SortByPTypeProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool SortByPTypeProcess::IsActive(unsigned int pFlags) const { bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {

View File

@ -60,17 +60,19 @@ namespace Assimp {
*/ */
class ASSIMP_API SortByPTypeProcess : public BaseProcess { class ASSIMP_API SortByPTypeProcess : public BaseProcess {
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
SortByPTypeProcess(); 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: private:
int mConfigRemoveMeshes; int mConfigRemoveMeshes;

View File

@ -40,7 +40,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/// @file SplitByBoneCountProcess.cpp /// @file SplitByBoneCountProcess.cpp
/// Implementation of the SplitByBoneCount postprocessing step /// Implementation of the SplitByBoneCount postprocessing step
@ -59,47 +58,36 @@ using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor // Constructor
SplitByBoneCountProcess::SplitByBoneCountProcess() SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {
{ // empty
// set default, might be overridden by importer config
mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES;
} }
// ------------------------------------------------------------------------------------------------
// Destructor
SplitByBoneCountProcess::~SplitByBoneCountProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag. // 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); return !!(pFlags & aiProcess_SplitByBoneCount);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Updates internal properties // 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); mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // 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"); ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin");
// early out // early out
bool isNecessary = false; bool isNecessary = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) {
{
isNecessary = true; isNecessary = true;
break; break;
} }
if( !isNecessary ) if( !isNecessary ) {
{
ASSIMP_LOG_DEBUG("SplitByBoneCountProcess early-out: no meshes with more than ", mMaxBoneCount, " bones." ); ASSIMP_LOG_DEBUG("SplitByBoneCountProcess early-out: no meshes with more than ", mMaxBoneCount, " bones." );
return; return;
} }
@ -111,28 +99,23 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
// build a new array of meshes for the scene // build a new array of meshes for the scene
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
{
aiMesh* srcMesh = pScene->mMeshes[a]; aiMesh* srcMesh = pScene->mMeshes[a];
std::vector<aiMesh*> newMeshes; std::vector<aiMesh*> newMeshes;
SplitMesh( pScene->mMeshes[a], newMeshes); SplitMesh( pScene->mMeshes[a], newMeshes);
// mesh was split // mesh was split
if( !newMeshes.empty() ) if( !newMeshes.empty() ) {
{
// store new meshes and indices of the new meshes // 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<unsigned int>(meshes.size())); mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
meshes.push_back( newMeshes[b]); meshes.push_back( newMeshes[b]);
} }
// and destroy the source mesh. It should be completely contained inside the new submeshes // and destroy the source mesh. It should be completely contained inside the new submeshes
delete srcMesh; delete srcMesh;
} } else {
else
{
// Mesh is kept unchanged - store it's new place in the mesh array // Mesh is kept unchanged - store it's new place in the mesh array
mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size())); mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
meshes.push_back( srcMesh); meshes.push_back( srcMesh);
@ -153,11 +136,9 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Splits the given mesh by bone count. // Splits the given mesh by bone count.
void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const {
{
// skip if not necessary // skip if not necessary
if( pMesh->mNumBones <= mMaxBoneCount ) if( pMesh->mNumBones <= mMaxBoneCount ) {
{
return; return;
} }
@ -165,17 +146,13 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
// TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
typedef std::pair<unsigned int, float> BoneWeight; typedef std::pair<unsigned int, float> BoneWeight;
std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices); std::vector< std::vector<BoneWeight> > 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]; const aiBone* bone = pMesh->mBones[a];
for( unsigned int b = 0; b < bone->mNumWeights; ++b) for( unsigned int b = 0; b < bone->mNumWeights; ++b) {
{ if (bone->mWeights[b].mWeight > 0.0f) {
if (bone->mWeights[b].mWeight > 0.0f)
{
int vertexId = bone->mWeights[b].mVertexId; int vertexId = bone->mWeights[b].mVertexId;
vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight); vertexBones[vertexId].emplace_back(a, bone->mWeights[b].mWeight);
if (vertexBones[vertexId].size() > mMaxBoneCount) if (vertexBones[vertexId].size() > mMaxBoneCount) {
{
throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!"); throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
} }
} }
@ -184,8 +161,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
unsigned int numFacesHandled = 0; unsigned int numFacesHandled = 0;
std::vector<bool> isFaceHandled( pMesh->mNumFaces, false); std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
while( numFacesHandled < pMesh->mNumFaces ) while( numFacesHandled < pMesh->mNumFaces ) {
{
// which bones are used in the current submesh // which bones are used in the current submesh
unsigned int numBones = 0; unsigned int numBones = 0;
std::vector<bool> isBoneUsed( pMesh->mNumBones, false); std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
@ -196,11 +172,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
unsigned int numSubMeshVertices = 0; unsigned int numSubMeshVertices = 0;
// add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit // add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) {
{
// skip if the face is already stored in a submesh // skip if the face is already stored in a submesh
if( isFaceHandled[a] ) if( isFaceHandled[a] ) {
{
continue; continue;
} }
// a small local set of new bones for the current face. State of all used bones for that face // a small local set of new bones for the current face. State of all used bones for that face
@ -209,30 +183,24 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
// check every vertex if its bones would still fit into the current submesh // check every vertex if its bones would still fit into the current submesh
for( unsigned int b = 0; b < face.mNumIndices; ++b ) for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
{
const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]]; const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
for( unsigned int c = 0; c < vb.size(); ++c) for( unsigned int c = 0; c < vb.size(); ++c) {
{
unsigned int boneIndex = vb[c].first; unsigned int boneIndex = vb[c].first;
if( !isBoneUsed[boneIndex] ) if( !isBoneUsed[boneIndex] ) {
{
newBonesAtCurrentFace.insert(boneIndex); newBonesAtCurrentFace.insert(boneIndex);
} }
} }
} }
// leave out the face if the new bones required for this face don't fit the bone count limit anymore // 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; continue;
} }
// mark all new bones as necessary // mark all new bones as necessary
for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it) {
{ if (!isBoneUsed[*it]) {
if (!isBoneUsed[*it])
{
isBoneUsed[*it] = true; isBoneUsed[*it] = true;
numBones++; numBones++;
} }
@ -261,27 +229,21 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
newMesh->mNumVertices = numSubMeshVertices; newMesh->mNumVertices = numSubMeshVertices;
newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size()); newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
newMesh->mVertices = new aiVector3D[newMesh->mNumVertices]; newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
if( pMesh->HasNormals() ) if( pMesh->HasNormals() ) {
{
newMesh->mNormals = new aiVector3D[newMesh->mNumVertices]; newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
} }
if( pMesh->HasTangentsAndBitangents() ) if( pMesh->HasTangentsAndBitangents() ) {
{
newMesh->mTangents = new aiVector3D[newMesh->mNumVertices]; newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices]; newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices];
} }
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) {
{ if( pMesh->HasTextureCoords( a) ) {
if( pMesh->HasTextureCoords( a) )
{
newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices]; newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
} }
newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
} }
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) {
{ if( pMesh->HasVertexColors( a) ) {
if( pMesh->HasVertexColors( a) )
{
newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices]; newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
} }
} }
@ -290,41 +252,33 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
newMesh->mFaces = new aiFace[subMeshFaces.size()]; newMesh->mFaces = new aiFace[subMeshFaces.size()];
unsigned int nvi = 0; // next vertex index unsigned int nvi = 0; // next vertex index
std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::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]]; const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
aiFace& dstFace = newMesh->mFaces[a]; aiFace& dstFace = newMesh->mFaces[a];
dstFace.mNumIndices = srcFace.mNumIndices; dstFace.mNumIndices = srcFace.mNumIndices;
dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
// accumulate linearly all the vertices of the source face // 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]; unsigned int srcIndex = srcFace.mIndices[b];
dstFace.mIndices[b] = nvi; dstFace.mIndices[b] = nvi;
previousVertexIndices[nvi] = srcIndex; previousVertexIndices[nvi] = srcIndex;
newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
if( pMesh->HasNormals() ) if( pMesh->HasNormals() ) {
{
newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
} }
if( pMesh->HasTangentsAndBitangents() ) if( pMesh->HasTangentsAndBitangents() ) {
{
newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
} }
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
{ if( pMesh->HasTextureCoords( c) ) {
if( pMesh->HasTextureCoords( c) )
{
newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
} }
} }
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
{ if( pMesh->HasVertexColors( c) ) {
if( pMesh->HasVertexColors( c) )
{
newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
} }
} }
@ -340,10 +294,8 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
newMesh->mBones = new aiBone*[numBones]; newMesh->mBones = new aiBone*[numBones];
std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max()); std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max());
for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) {
{ if( !isBoneUsed[a] ) {
if( !isBoneUsed[a] )
{
continue; continue;
} }
@ -360,24 +312,20 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
ai_assert( newMesh->mNumBones == numBones ); ai_assert( newMesh->mNumBones == numBones );
// iterate over all new vertices and count which bones affected its old vertex in the source mesh // 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]; unsigned int oldIndex = previousVertexIndices[a];
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex]; const std::vector<BoneWeight>& 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 ]; unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
if( newBoneIndex != std::numeric_limits<unsigned int>::max() ) if( newBoneIndex != std::numeric_limits<unsigned int>::max() ) {
{
newMesh->mBones[newBoneIndex]->mNumWeights++; newMesh->mBones[newBoneIndex]->mNumWeights++;
} }
} }
} }
// allocate all bone weight arrays accordingly // 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]; aiBone* bone = newMesh->mBones[a];
ai_assert( bone->mNumWeights > 0 ); ai_assert( bone->mNumWeights > 0 );
bone->mWeights = new aiVertexWeight[bone->mNumWeights]; bone->mWeights = new aiVertexWeight[bone->mNumWeights];
@ -385,16 +333,14 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
} }
// now copy all the bone vertex weights for all the vertices which made it into the new submesh // now copy all the bone vertex weights for all the vertices which made it into the new submesh
for( unsigned int a = 0; a < numSubMeshVertices; ++a) for( unsigned int a = 0; a < numSubMeshVertices; ++a) {
{
// find the source vertex for it in the source mesh // find the source vertex for it in the source mesh
unsigned int previousIndex = previousVertexIndices[a]; unsigned int previousIndex = previousVertexIndices[a];
// these bones were affecting it // these bones were affecting it
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex]; const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex];
// all of the bones affecting it should be present in the new submesh, or else // all of the bones affecting it should be present in the new submesh, or else
// the face it comprises shouldn't be present // 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 ]; unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() ); ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() );
aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights; aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights;
@ -450,14 +396,11 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Recursively updates the node's mesh list to account for the changed mesh list // Recursively updates the node's mesh list to account for the changed mesh list
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const {
{
// rebuild the node's mesh index list // rebuild the node's mesh index list
if( pNode->mNumMeshes > 0 ) if( pNode->mNumMeshes == 0 ) {
{
std::vector<unsigned int> newMeshList; std::vector<unsigned int> 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]; unsigned int srcIndex = pNode->mMeshes[a];
const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex]; const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex];
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); 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 // 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]); UpdateNode( pNode->mChildren[a]);
} }
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, 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 <assimp/mesh.h> #include <assimp/mesh.h>
#include <assimp/scene.h> #include <assimp/scene.h>
namespace Assimp namespace Assimp {
{
/** Postprocessing filter to split meshes with many bones into submeshes /** Postprocessing filter to split meshes with many bones into submeshes
* so that each submesh has a certain max bone count. * so that each submesh has a certain max bone count.
@ -61,34 +58,29 @@ namespace Assimp
* Applied BEFORE the JoinVertices-Step occurs. * Applied BEFORE the JoinVertices-Step occurs.
* Returns NON-UNIQUE vertices, splits by bone count. * Returns NON-UNIQUE vertices, splits by bone count.
*/ */
class SplitByBoneCountProcess : public BaseProcess class SplitByBoneCountProcess : public BaseProcess {
{
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
SplitByBoneCountProcess(); SplitByBoneCountProcess();
~SplitByBoneCountProcess(); ~SplitByBoneCountProcess() override = default;
public: /// @brief Returns whether the processing step is present in the given flag.
/** Returns whether the processing step is present in the given flag. /// @param pFlags The processing flags the importer was called with. A
* @param pFlags The processing flags the importer was called with. A /// bitwise combination of #aiPostProcessSteps.
* bitwise combination of #aiPostProcessSteps. /// @return true if the process is present in this flag fields, false if not.
* @return true if the process is present in this flag fields, bool IsActive( unsigned int pFlags) const override;
* false if not.
*/
bool IsActive( unsigned int pFlags) const;
/** Called prior to ExecuteOnScene(). /// @brief Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration /// The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. /// basing on the Importer's configuration property list.
*/ virtual void SetupProperties(const Importer* pImp) override;
virtual void SetupProperties(const Importer* pImp);
protected: protected:
/** Executes the post processing step on the given imported data. /// Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. /// At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. /// @param pScene The imported data to work at.
*/ void Execute( aiScene* pScene) override;
void Execute( aiScene* pScene);
/// Splits the given mesh by bone count. /// 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. /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.

View File

@ -55,9 +55,6 @@ SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
} }
// ------------------------------------------------------------------------------------------------
SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const { bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
@ -329,9 +326,6 @@ SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
} }
// ------------------------------------------------------------------------------------------------
SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const { bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {

View File

@ -83,16 +83,15 @@ class SplitLargeMeshesProcess_Vertex;
* Applied BEFORE the JoinVertices-Step occurs. * Applied BEFORE the JoinVertices-Step occurs.
* Returns NON-UNIQUE vertices, splits by triangle number. * 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; friend class SplitLargeMeshesProcess_Vertex;
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
SplitLargeMeshesProcess_Triangle(); SplitLargeMeshesProcess_Triangle();
~SplitLargeMeshesProcess_Triangle(); ~SplitLargeMeshesProcess_Triangle() override = default;
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag. /** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. A * @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, * @return true if the process is present in this flag fields,
* false if not. * false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ExecuteOnScene(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * 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 //! Set the split limit - needed for unit testing
inline void SetLimit(unsigned int l) inline void SetLimit(unsigned int l)
@ -119,14 +116,12 @@ public:
inline unsigned int GetLimit() const inline unsigned int GetLimit() const
{return LIMIT;} {return LIMIT;}
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Apply the algorithm to a given mesh //! Apply the algorithm to a given mesh
@ -144,36 +139,31 @@ public:
unsigned int LIMIT; unsigned int LIMIT;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Post-processing filter to split large meshes into sub-meshes /** Post-processing filter to split large meshes into sub-meshes
* *
* Applied AFTER the JoinVertices-Step occurs. * Applied AFTER the JoinVertices-Step occurs.
* Returns UNIQUE vertices, splits by vertex number. * Returns UNIQUE vertices, splits by vertex number.
*/ */
class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess {
{
public: public:
SplitLargeMeshesProcess_Vertex(); SplitLargeMeshesProcess_Vertex();
~SplitLargeMeshesProcess_Vertex(); ~SplitLargeMeshesProcess_Vertex() override = default;
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag field.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with. A bitwise
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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(). /** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * 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 //! Set the split limit - needed for unit testing
inline void SetLimit(unsigned int l) inline void SetLimit(unsigned int l)
@ -183,14 +173,12 @@ public:
inline unsigned int GetLimit() const inline unsigned int GetLimit() const
{return LIMIT;} {return LIMIT;}
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Apply the algorithm to a given mesh //! Apply the algorithm to a given mesh

View File

@ -56,33 +56,24 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
TextureTransformStep::TextureTransformStep() : TextureTransformStep::TextureTransformStep() : configFlags() {
configFlags()
{
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
TextureTransformStep::~TextureTransformStep() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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; return (pFlags & aiProcess_TransformUVCoords) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup properties // 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); 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. /* This function tries to simplify the input UV transformation.
* That's very important as it allows us to reduce the number * That's very important as it allows us to reduce the number
* of output UV channels. The order in which the transformations * of output UV channels. The order in which the transformations
@ -90,7 +81,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
*/ */
int rounded; int rounded;
char szTemp[512]; char szTemp[512] = {};
/* Optimize the rotation angle. That's slightly difficult as /* Optimize the rotation angle. That's slightly difficult as
* we have an inprecise floating-point number (when comparing * 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 * an epsilon of 5 degrees). If there is a rotation value, we can't
* perform any further optimizations. * perform any further optimizations.
*/ */
if (info.mRotation) if (info.mRotation) {
{
float out = info.mRotation; float out = info.mRotation;
rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI))); rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)));
if (rounded) if (rounded) {
{
out -= rounded * static_cast<float>(AI_MATH_PI); out -= rounded * static_cast<float>(AI_MATH_PI);
ASSIMP_LOG_INFO("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out); 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<TTUpdateInfo>& l, unsigned int n) void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n) {
{
// Don't set if == 0 && wasn't set before // Don't set if == 0 && wasn't set before
for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) { for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
const TTUpdateInfo& info = *it; const TTUpdateInfo& info = *it;
@ -203,8 +191,7 @@ void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
inline const char* MappingModeToChar(aiTextureMapMode map) inline static const char* MappingModeToChar(aiTextureMapMode map) {
{
if (aiTextureMapMode_Wrap == map) if (aiTextureMapMode_Wrap == map)
return "-w"; 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"); ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin");

View File

@ -193,28 +193,23 @@ struct STransformVecInfo : public aiUVTransform {
/** Helper step to compute final UV coordinate sets if there are scalings /** Helper step to compute final UV coordinate sets if there are scalings
* or rotations in the original data read from the file. * or rotations in the original data read from the file.
*/ */
class TextureTransformStep : public BaseProcess class TextureTransformStep : public BaseProcess {
{
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
TextureTransformStep(); TextureTransformStep();
~TextureTransformStep(); ~TextureTransformStep() override = default;
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;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Preprocess a specific UV transformation setup /** Preprocess a specific UV transformation setup
* *
@ -223,10 +218,9 @@ protected:
void PreProcessUVTransform(STransformVecInfo& info); void PreProcessUVTransform(STransformVecInfo& info);
private: private:
unsigned int configFlags; unsigned int configFlags;
}; };
} } // namespace Assimp
#endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED #endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED

View File

@ -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. // Returns whether the processing step is present in the given flag field.
bool TriangulateProcess::IsActive( unsigned int pFlags) const bool TriangulateProcess::IsActive( unsigned int pFlags) const
@ -468,6 +459,21 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
continue; 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 // and no other point may be contained in this triangle
for ( tmp = 0; tmp < max; ++tmp) { for ( tmp = 0; tmp < max; ++tmp) {

View File

@ -61,8 +61,10 @@ namespace Assimp {
*/ */
class ASSIMP_API TriangulateProcess : public BaseProcess { class ASSIMP_API TriangulateProcess : public BaseProcess {
public: 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. /** Returns whether the processing step is present in the given flag field.
@ -70,14 +72,14 @@ public:
* combination of #aiPostProcessSteps. * combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @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. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Triangulates the given mesh. /** Triangulates the given mesh.

View File

@ -60,12 +60,7 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ValidateDSProcess::ValidateDSProcess() : ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
mScene() {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ValidateDSProcess::~ValidateDSProcess() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // 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); nodeName, pNode->mNumChildren);
} }
for (unsigned int i = 0; i < pNode->mNumChildren; ++i) { 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);
}
} }
} }
} }

View File

@ -69,22 +69,20 @@ namespace Assimp {
/** Validates the whole ASSIMP scene data structure for correctness. /** Validates the whole ASSIMP scene data structure for correctness.
* ImportErrorException is thrown of the scene is corrupt.*/ * ImportErrorException is thrown of the scene is corrupt.*/
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class ValidateDSProcess : public BaseProcess class ValidateDSProcess : public BaseProcess {
{
public: public:
// -------------------------------------------------------------------
/// The default class constructor / destructor.
ValidateDSProcess(); ValidateDSProcess();
~ValidateDSProcess(); ~ValidateDSProcess() override = default;
public:
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void Execute( aiScene* pScene); bool IsActive( unsigned int pFlags) const override;
// -------------------------------------------------------------------
void Execute( aiScene* pScene) override;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Report a validation error. This will throw an exception, /** Report a validation error. This will throw an exception,
* control won't return. * control won't return.

View File

@ -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 no warranty implied; use at your own risk
Do this: Do this:
@ -48,6 +48,8 @@ LICENSE
RECENT REVISION HISTORY: 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.26 (2020-07-13) many minor fixes
2.25 (2020-02-02) fix warnings 2.25 (2020-02-02) fix warnings
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically 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) Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
Arseny Kapoulkine Arseny Kapoulkine Simon Breuss (16-bit PNM)
John-Mark Allen John-Mark Allen
Carmelo J Fdez-Aguera Carmelo J Fdez-Aguera
@ -102,19 +104,21 @@ RECENT REVISION HISTORY:
Thomas Ruf Ronny Chevalier github:rlyeh Thomas Ruf Ronny Chevalier github:rlyeh
Janez Zemva John Bartholomew Michal Cichon github:romigrou Janez Zemva John Bartholomew Michal Cichon github:romigrou
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk 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 Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
Cass Everitt Ryamond Barbiero github:grim210 Cass Everitt Ryamond Barbiero github:grim210
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus 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 Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 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] Luca Sas Alexander Veselov Zack Middleton [reserved]
Ryan C. Gordon [reserved] [reserved] Ryan C. Gordon [reserved] [reserved]
DO NOT ADD YOUR NAME HERE 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. 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 80% of merge conflicts on stb PRs are due to people adding their name at the end
of the credits. of the credits.
@ -137,7 +141,7 @@ RECENT REVISION HISTORY:
// // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... x = width, y = height, n = # 8-bit components per pixel ...
// // ... replace '0' with '1'..'4' to force that many 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 // // ... 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: // Standard parameters:
// int *x -- outputs image width in pixels // int *x -- outputs image width in pixels
@ -176,6 +180,32 @@ RECENT REVISION HISTORY:
// //
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // 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: // UNICODE:
@ -281,11 +311,10 @@ RECENT REVISION HISTORY:
// //
// iPhone PNG support: // iPhone PNG support:
// //
// By default we convert iphone-formatted PNGs back to RGB, even though // We optionally support converting iPhone-formatted PNGs (which store
// they are internally encoded differently. You can disable this conversion // premultiplied BGRA) back to RGB, even though they're internally encoded
// by calling stbi_convert_iphone_png_to_rgb(0), in which case // differently. To enable this conversion, call
// you will always just get the native iphone "format" through (which // stbi_convert_iphone_png_to_rgb(1).
// is BGR stored in RGB).
// //
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // 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 // 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 // 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; // this function is only available if your compiler supports thread-local variables;
// calling it will fail to link if your compiler doesn't // 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); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes // 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
#endif #endif
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__SYMBIAN32__)
typedef unsigned short stbi__uint16; typedef unsigned short stbi__uint16;
typedef signed short stbi__int16; typedef signed short stbi__int16;
typedef unsigned int stbi__uint32; typedef unsigned int stbi__uint32;
@ -634,7 +665,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#ifdef STBI_HAS_LROTL #ifdef STBI_HAS_LROTL
#define stbi_lrot(x,y) _lrotl(x,y) #define stbi_lrot(x,y) _lrotl(x,y)
#else #else
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31)))
#endif #endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) #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 #ifdef STBI_NEON
#include <arm_neon.h> #include <arm_neon.h>
// 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))) #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif #endif
#endif
#ifndef STBI_SIMD_ALIGN #ifndef STBI_SIMD_ALIGN
#define STBI_SIMD_ALIGN(type, name) type name #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 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 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_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__pnm_is16(stbi__context *s);
#endif #endif
static 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 // 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) 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) && 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); 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) 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; 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 #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__err - error
// stbi__errpf - error returning pointer to float // stbi__errpf - error returning pointer to float
// stbi__errpuc - error returning pointer to unsigned char // 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->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; ri->num_channels = 0;
#ifndef STBI_NO_JPEG // test the formats with a very explicit header first (at least a FOURCC
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); // or distinctive magic number first)
#endif
#ifndef STBI_NO_PNG #ifndef STBI_NO_PNG
if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
#endif #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 #ifndef STBI_NO_PIC
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
#endif #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 #ifndef STBI_NO_PNM
if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
#endif #endif
@ -1262,12 +1320,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in
#ifndef STBI_NO_STDIO #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 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); 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 #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) 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); 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) static FILE *stbi__fopen(char const *filename, char const *mode)
{ {
FILE *f; FILE *f;
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
wchar_t wMode[64]; wchar_t wMode[64];
wchar_t wFilename[1024]; 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; 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; return 0;
#if _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode)) if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0; f = 0;
#else #else
@ -1662,7 +1720,8 @@ static int stbi__get16le(stbi__context *s)
static stbi__uint32 stbi__get32le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s)
{ {
stbi__uint32 z = stbi__get16le(s); stbi__uint32 z = stbi__get16le(s);
return z + (stbi__get16le(s) << 16); z += (stbi__uint32)stbi__get16le(s) << 16;
return z;
} }
#endif #endif
@ -1944,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
int i,j,k=0; int i,j,k=0;
unsigned int code; unsigned int code;
// build size list for each symbol (from JPEG spec) // build size list for each symbol (from JPEG spec)
for (i=0; i < 16; ++i) for (i=0; i < 16; ++i) {
for (j=0; j < count[i]; ++j) for (j=0; j < count[i]; ++j) {
h->size[k++] = (stbi_uc) (i+1); h->size[k++] = (stbi_uc) (i+1);
if(k >= 257) return stbi__err("bad size list","Corrupt JPEG");
}
}
h->size[k] = 0; h->size[k] = 0;
// compute actual symbols (from jpeg spec) // 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 // convert the huffman code to the symbol id
c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; 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]); STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
// convert the id to a symbol // 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; unsigned int k;
int sgn; int sgn;
if (j->code_bits < n) stbi__grow_buffer_unsafe(j); 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); 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]; j->code_buffer = k & ~stbi__bmask[n];
k &= stbi__bmask[n]; k &= stbi__bmask[n];
j->code_bits -= n; j->code_bits -= n;
return k + (stbi__jbias[n] & ~sgn); return k + (stbi__jbias[n] & (sgn - 1));
} }
// get some unsigned bits // get some unsigned bits
@ -2104,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
{ {
unsigned int k; unsigned int k;
if (j->code_bits < n) stbi__grow_buffer_unsafe(j); 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); k = stbi_lrot(j->code_buffer, n);
j->code_buffer = k & ~stbi__bmask[n]; j->code_buffer = k & ~stbi__bmask[n];
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; unsigned int k;
if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); 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; k = j->code_buffer;
j->code_buffer <<= 1; j->code_buffer <<= 1;
--j->code_bits; --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); if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
t = stbi__jpeg_huff_decode(j, hdc); 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 // 0 all the ac values now so we can do it 32-bits at a time
memset(data,0,64*sizeof(data[0])); memset(data,0,64*sizeof(data[0]));
diff = t ? stbi__extend_receive(j, t) : 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; dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc; 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]); data[0] = (short) (dc * dequant[0]);
// decode AC components, see JPEG spec // 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 if (r) { // fast-AC path
k += (r >> 4) & 15; // run k += (r >> 4) & 15; // run
s = r & 15; // combined length 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_buffer <<= s;
j->code_bits -= s; j->code_bits -= s;
// decode into unzigzag'd location // 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 // first scan for DC coefficient, must be first
memset(data,0,64*sizeof(data[0])); // 0 all the ac values now memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
t = stbi__jpeg_huff_decode(j, hdc); 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; 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; dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc; 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 { } else {
// refinement scan for DC coefficient // refinement scan for DC coefficient
if (stbi__jpeg_get_bit(j)) 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 if (r) { // fast-AC path
k += (r >> 4) & 15; // run k += (r >> 4) & 15; // run
s = r & 15; // combined length 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_buffer <<= s;
j->code_bits -= s; j->code_bits -= s;
zig = stbi__jpeg_dezigzag[k++]; zig = stbi__jpeg_dezigzag[k++];
data[zig] = (short) ((r >> 8) << shift); data[zig] = (short) ((r >> 8) * (1 << shift));
} else { } else {
int rs = stbi__jpeg_huff_decode(j, hac); int rs = stbi__jpeg_huff_decode(j, hac);
if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); 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 { } else {
k += r; k += r;
zig = stbi__jpeg_dezigzag[k++]; 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); } 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); sizes[i] = stbi__get8(z->s);
n += sizes[i]; 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; L -= 17;
if (tc == 0) { if (tc == 0) {
if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 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; 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 // compute interleaved mcu info
z->img_h_max = h_max; z->img_h_max = h_max;
z->img_v_max = v_max; z->img_v_max = v_max;
@ -3304,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
return 1; 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 // decode image to YCbCr format
static int stbi__decode_jpeg_image(stbi__jpeg *j) 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__process_scan_header(j)) return 0;
if (!stbi__parse_entropy_coded_data(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0;
if (j->marker == STBI__MARKER_none ) { if (j->marker == STBI__MARKER_none ) {
// handle 0s at the end of image data from IP Kamera 9060 j->marker = stbi__skip_jpeg_junk_at_end(j);
while (!stbi__at_eof(j->s)) {
int x = stbi__get8(j->s);
if (x == 255) {
j->marker = stbi__get8(j->s);
break;
}
}
// if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 // 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)) { } else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s); int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s);
if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); 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"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
} else {
if (!stbi__process_marker(j, m)) return 0;
}
m = stbi__get_marker(j); m = stbi__get_marker(j);
} else {
if (!stbi__process_marker(j, m)) return 1;
m = stbi__get_marker(j);
}
} }
if (j->progressive) if (j->progressive)
stbi__jpeg_finish(j); 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 else
decode_n = z->s->img_n; 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 // resample and color-convert
{ {
int k; 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; unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); 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); STBI_NOTUSED(ri);
j->s = s; j->s = s;
stbi__setup_jpeg(j); stbi__setup_jpeg(j);
@ -3936,6 +4041,8 @@ static int stbi__jpeg_test(stbi__context *s)
{ {
int r; int r;
stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); 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; j->s = s;
stbi__setup_jpeg(j); stbi__setup_jpeg(j);
r = stbi__decode_jpeg_header(j, STBI__SCAN_type); 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; int result;
stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); 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; j->s = s;
result = stbi__jpeg_info_raw(j, x, y, comp); result = stbi__jpeg_info_raw(j, x, y, comp);
STBI_FREE(j); 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 // 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_BITS 9 // accelerate all cases in default tables
#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet
// zlib-style huffman encoding // zlib-style huffman encoding
// (jpegs packs from left, zlib from right, so can't share code) // (jpegs packs from left, zlib from right, so can't share code)
@ -3988,8 +4098,8 @@ typedef struct
stbi__uint16 firstcode[16]; stbi__uint16 firstcode[16];
int maxcode[17]; int maxcode[17];
stbi__uint16 firstsymbol[16]; stbi__uint16 firstsymbol[16];
stbi_uc size[288]; stbi_uc size[STBI__ZNSYMS];
stbi__uint16 value[288]; stbi__uint16 value[STBI__ZNSYMS];
} stbi__zhuffman; } stbi__zhuffman;
stbi_inline static int stbi__bitreverse16(int n) 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! if (s >= 16) return -1; // invalid code!
// code size is s, so: // code size is s, so:
b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; 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. if (z->size[b] != s) return -1; // was originally an assert, but report failure instead.
a->code_buffer >>= s; a->code_buffer >>= s;
a->num_bits -= s; a->num_bits -= s;
@ -4201,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
a->zout = zout; a->zout = zout;
return 1; 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; z -= 257;
len = stbi__zlength_base[z]; len = stbi__zlength_base[z];
if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
z = stbi__zhuffman_decode(a, &a->z_distance); 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]; dist = stbi__zdist_base[z];
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[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"); 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; 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,
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 { } else {
if (type == 1) { if (type == 1) {
// use fixed code lengths // 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; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
} else { } else {
if (!stbi__compute_huffman_codes(a)) return 0; 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 // de-interlacing
final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); 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) { for (p=0; p < 7; ++p) {
int xorig[] = { 0,4,0,2,0,1,0 }; int xorig[] = { 0,4,0,2,0,1,0 };
int yorig[] = { 0,0,4,0,2,0,1 }; 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; return 1;
} }
static int stbi__unpremultiply_on_load = 0; static int stbi__unpremultiply_on_load_global = 0;
static int stbi__de_iphone_flag = 0; static int stbi__de_iphone_flag_global = 0;
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) 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) 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) static void stbi__de_iphone(stbi__png *z)
{ {
stbi__context *s = z->s; 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 palette[1024], pal_img_n=0;
stbi_uc has_trans=0, tc[3]={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; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
int first=1,k,interlace=0, color=0, is_iphone=0; int first=1,k,interlace=0, color=0, is_iphone=0;
stbi__context *s = z->s; 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) { if (!pal_img_n) {
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); 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 ((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 { } else {
// if paletted, then pal_n is our final components, and // if paletted, then pal_n is our final components, and
// img_n is # components to decompress/filter. // img_n is # components to decompress/filter.
s->img_n = 1; s->img_n = 1;
if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); 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; 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 (!(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"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
has_trans = 1; 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) { if (z->depth == 16) {
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
} else { } 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'): { case STBI__PNG_TYPE('I','D','A','T'): {
if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (first) return stbi__err("first not IHDR", "Corrupt PNG");
if (pal_img_n && !pal_len) return stbi__err("no PLTE","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 ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) { if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit; stbi__uint32 idata_limit_old = idata_limit;
@ -5272,6 +5418,32 @@ typedef struct
int extra_read; int extra_read;
} stbi__bmp_data; } 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) static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{ {
int hsz; int hsz;
@ -5299,6 +5471,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
if (hsz != 12) { if (hsz != 12) {
int compress = stbi__get32le(s); int compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); 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 sizeof
stbi__get32le(s); // discard hres stbi__get32le(s); // discard hres
stbi__get32le(s); // discard vres 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 (info->bpp == 16 || info->bpp == 32) {
if (compress == 0) { if (compress == 0) {
if (info->bpp == 32) { stbi__bmp_set_mask_defaults(info, compress);
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;
}
} else if (compress == 3) { } else if (compress == 3) {
info->mr = stbi__get32le(s); info->mr = stbi__get32le(s);
info->mg = 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"); return stbi__errpuc("bad BMP", "bad BMP");
} }
} else { } else {
// V4/V5 header
int i; int i;
if (hsz != 108 && hsz != 124) if (hsz != 108 && hsz != 124)
return stbi__errpuc("bad BMP", "bad BMP"); 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->mg = stbi__get32le(s);
info->mb = stbi__get32le(s); info->mb = stbi__get32le(s);
info->ma = 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 stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i) for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters 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; psize = (info.offset - info.extra_read - info.hsz) >> 2;
} }
if (psize == 0) { if (psize == 0) {
STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); // accept some number of extra bytes after the header, but if the offset points either to before
if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { // 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"); 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 // intermediate buffer is RGBA
result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); 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); memset(result, 0xff, x*y*4);
if (!stbi__pic_load_core(s,x,y,comp, result)) { 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) 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)); 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)) { if (!stbi__gif_header(s, g, comp, 1)) {
STBI_FREE(g); STBI_FREE(g);
stbi__rewind( s ); 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) 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)) { 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_uc *two_back = 0;
stbi__gif g; stbi__gif g;
int stride; int stride;
int out_size = 0;
int delays_size = 0;
STBI_NOTUSED(out_size);
STBI_NOTUSED(delays_size);
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
if (delays) { if (delays) {
*delays = 0; *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; stride = g.w * g.h * 4;
if (out) { if (out) {
void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
if (NULL == tmp) { if (!tmp)
STBI_FREE(g.out); return stbi__load_gif_main_outofmem(&g, out, delays);
STBI_FREE(g.history);
STBI_FREE(g.background);
return stbi__errpuc("outofmem", "Out of memory");
}
else { else {
out = (stbi_uc*) tmp; out = (stbi_uc*) tmp;
out_size = layers * stride;
} }
if (delays) { 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 { } else {
out = (stbi_uc*)stbi__malloc( layers * stride ); out = (stbi_uc*)stbi__malloc( layers * stride );
if (!out)
return stbi__load_gif_main_outofmem(&g, out, delays);
out_size = layers * stride;
if (delays) { if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) ); *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 ); 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 // Run
value = stbi__get8(s); value = stbi__get8(s);
count -= 128; 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) for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = value; scanline[i++ * 4 + k] = value;
} else { } else {
// Dump // 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) for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = stbi__get8(s); 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; info.all_a = 255;
p = stbi__bmp_parse_header(s, &info); p = stbi__bmp_parse_header(s, &info);
if (p == NULL) {
stbi__rewind( s ); stbi__rewind( s );
if (p == NULL)
return 0; return 0;
}
if (x) *x = s->img_x; if (x) *x = s->img_x;
if (y) *y = s->img_y; if (y) *y = s->img_y;
if (comp) { if (comp) {
@ -7200,8 +7407,8 @@ static int stbi__psd_is16(stbi__context *s)
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
(void) stbi__get32be(s); STBI_NOTUSED(stbi__get32be(s));
(void) stbi__get32be(s); STBI_NOTUSED(stbi__get32be(s));
depth = stbi__get16be(s); depth = stbi__get16be(s);
if (depth != 16) { if (depth != 16) {
stbi__rewind( s ); stbi__rewind( s );
@ -7280,7 +7487,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
// Known limitations: // Known limitations:
// Does not support comments in the header section // Does not support comments in the header section
// Does not support ASCII image data (formats P2 and P3) // Does not support ASCII image data (formats P2 and P3)
// Does not support 16-bit-per-channel
#ifndef STBI_NO_PNM #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_uc *out;
STBI_NOTUSED(ri); 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; return 0;
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); 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; *y = s->img_y;
if (comp) *comp = s->img_n; 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"); 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"); 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) { if (req_comp && req_comp != s->img_n) {
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); 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 if (out == NULL) return out; // stbi__convert_format frees input on failure
} }
return out; 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)) { while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
value = value*10 + (*c - '0'); value = value*10 + (*c - '0');
*c = (char) stbi__get8(s); *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; 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); stbi__pnm_skip_whitespace(s, &c);
*x = stbi__pnm_getinteger(s, &c); // read width *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); stbi__pnm_skip_whitespace(s, &c);
*y = stbi__pnm_getinteger(s, &c); // read height *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); stbi__pnm_skip_whitespace(s, &c);
maxv = stbi__pnm_getinteger(s, &c); // read max value maxv = stbi__pnm_getinteger(s, &c); // read max value
if (maxv > 65535)
if (maxv > 255) return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images");
return stbi__err("max value > 255", "PPM image not 8-bit"); else if (maxv > 255)
return 16;
else else
return 8;
}
static int stbi__pnm_is16(stbi__context *s)
{
if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)
return 1; return 1;
return 0;
} }
#endif #endif
@ -7452,6 +7680,9 @@ static int stbi__is_16_main(stbi__context *s)
if (stbi__psd_is16(s)) return 1; if (stbi__psd_is16(s)) return 1;
#endif #endif
#ifndef STBI_NO_PNM
if (stbi__pnm_is16(s)) return 1;
#endif
return 0; return 0;
} }

View File

@ -103,7 +103,7 @@ int cryptrand(unsigned char *buf, unsigned int len)
unsigned __int64 pentium_tsc[1]; unsigned __int64 pentium_tsc[1];
int result = 0; 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)) if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{ {
result = CryptGenRandom(provider, len, buf); result = CryptGenRandom(provider, len, buf);
@ -111,6 +111,7 @@ int cryptrand(unsigned char *buf, unsigned int len)
if (result) if (result)
return len; return len;
} }
#endif
for (rlen = 0; rlen < (int)len; ++rlen) for (rlen = 0; rlen < (int)len; ++rlen)
{ {

View File

@ -76,7 +76,15 @@ if(MSVC)
set(CMAKE_DEBUG_POSTFIX "d") set(CMAKE_DEBUG_POSTFIX "d")
add_definitions(-D_CRT_SECURE_NO_DEPRECATE) add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_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}) 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() endif()
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)

View File

@ -115,6 +115,10 @@ def _init(self, target = None, parent = None):
if m.startswith("_"): if m.startswith("_"):
continue continue
# We should not be accessing `mPrivate` according to structs.Scene.
if m == 'mPrivate':
continue
if m.startswith('mNum'): if m.startswith('mNum'):
if 'm' + m[4:] in dirself: if 'm' + m[4:] in dirself:
continue # will be processed later on continue # will be processed later on
@ -211,7 +215,7 @@ def _init(self, target = None, parent = None):
else: # starts with 'm' but not iterable 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)) + ")") logger.debug("Added " + name + " as self." + name + " (type: " + str(type(obj)) + ")")
if _is_init_type(obj): if _is_init_type(obj):

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Some files were not shown because too many files have changed in this diff Show More