Merge branch 'master' into kimkulling/fix_artifact_export
commit
ec142d42bb
|
@ -57,3 +57,13 @@ jobs:
|
|||
- name: test
|
||||
run: cd build/bin && ./unit
|
||||
shell: bash
|
||||
|
||||
job3:
|
||||
name: printf-sanitizer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: run scan_printf script
|
||||
run: ./scripts/scan_printf.sh
|
||||
shell: bash
|
||||
|
|
|
@ -138,7 +138,7 @@ IF (WIN32)
|
|||
ELSE()
|
||||
OPTION( ASSIMP_BUILD_ZLIB
|
||||
"Build your own zlib"
|
||||
OFF
|
||||
ON
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
|
|
@ -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.
|
41
Readme.md
41
Readme.md
|
@ -1,6 +1,8 @@
|
|||
Open Asset Import Library (assimp)
|
||||
==================================
|
||||
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
||||
|
||||
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
|
||||
|
||||
### Current project status ###
|
||||
[](https://opencollective.com/assimp)
|
||||

|
||||
|
@ -14,7 +16,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
|
|||
[](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
|
||||
[](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
|
||||
[](https://lgtm.com/projects/g/assimp/assimp/alerts/)
|
||||
<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.
|
||||
|
@ -23,15 +24,19 @@ Additionally, assimp features various __mesh post processing tools__: normals an
|
|||
### Latest Doc's ###
|
||||
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
|
||||
|
||||
### Get involved ###
|
||||
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
|
||||
<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
|
||||
### Prebuild binaries ###
|
||||
Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib)
|
||||
|
||||
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
|
||||
|
||||
### Communities ###
|
||||
- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions)
|
||||
- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/)
|
||||
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
|
||||
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
|
||||
|
||||
And we also have a Gitter-channel:Gitter [](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
|
||||
|
||||
#### Supported file formats ####
|
||||
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md)
|
||||
|
||||
|
@ -66,28 +71,18 @@ Open Asset Import Library is implemented in C++. The directory structure looks l
|
|||
/port Ports to other languages and scripts to maintain those.
|
||||
/test Unit- and regression tests, test suite of models
|
||||
/tools Tools (old assimp viewer, command line `assimp`)
|
||||
/samples A small number of samples to illustrate possible
|
||||
use cases for Assimp
|
||||
/samples A small number of samples to illustrate possible use-cases for Assimp
|
||||
|
||||
The source code is organized in the following way:
|
||||
|
||||
code/Common The base implementation for importers and the infrastructure
|
||||
code/CApi Special implementations which are only used for the C-API
|
||||
code/Geometry A collection of geometry tools
|
||||
code/Material The material system
|
||||
code/PBR An exporter for physical based models
|
||||
code/PostProcessing The post-processing steps
|
||||
code/AssetLib/<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 [](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
|
||||
|
||||
### Contributing ###
|
||||
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
||||
a pull request with your changes against the main repository's `master` branch.
|
||||
|
|
|
@ -397,10 +397,6 @@ struct Material {
|
|||
|
||||
Material(const Material &other) = default;
|
||||
|
||||
Material(Material &&other) AI_NO_EXCEPT = default;
|
||||
|
||||
Material &operator=(Material &&other) AI_NO_EXCEPT = default;
|
||||
|
||||
virtual ~Material() = default;
|
||||
|
||||
//! Name of the material
|
||||
|
|
|
@ -266,8 +266,15 @@ void Discreet3DSImporter::ParseMainChunk() {
|
|||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code-return"
|
||||
#endif
|
||||
// recursively continue processing this hierarchy level
|
||||
return ParseMainChunk();
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -68,7 +68,7 @@ using namespace D3DS;
|
|||
class Discreet3DSImporter : public BaseImporter {
|
||||
public:
|
||||
Discreet3DSImporter();
|
||||
~Discreet3DSImporter();
|
||||
~Discreet3DSImporter() override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~EmbeddedTexture() = default;
|
||||
~EmbeddedTexture() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_EmbeddedTexture2D;
|
||||
|
@ -110,7 +110,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~Texture2DGroup() = default;
|
||||
~Texture2DGroup() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_Texture2DGroup;
|
||||
|
@ -127,7 +127,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~BaseMaterials() = default;
|
||||
~BaseMaterials() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_BaseMaterials;
|
||||
|
@ -152,7 +152,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~Object() = default;
|
||||
~Object() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_Object;
|
||||
|
|
|
@ -282,11 +282,11 @@ public:
|
|||
bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
|
||||
bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
|
||||
bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
|
||||
void Throw_CloseNotFound(const std::string &nodeName);
|
||||
void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName);
|
||||
void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName);
|
||||
void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription);
|
||||
void Throw_ID_NotFound(const std::string &pID) const;
|
||||
AI_WONT_RETURN void Throw_CloseNotFound(const std::string &nodeName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_ID_NotFound(const std::string &pID) const AI_WONT_RETURN_SUFFIX;
|
||||
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
|
||||
bool XML_SearchNode(const std::string &nodeName);
|
||||
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
|
||||
|
|
|
@ -815,6 +815,7 @@ nl_clean_loop:
|
|||
for (; next_it != nodeArray.end(); ++next_it) {
|
||||
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
|
||||
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
|
||||
// FIXME: this leaks memory on test models test8.amf and test9.amf
|
||||
nodeArray.erase(nl_it);
|
||||
|
||||
goto nl_clean_loop;
|
||||
|
|
|
@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
// internal headers
|
||||
|
@ -322,21 +321,6 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
|
|||
aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
|
||||
nd->mNodeName.Set(me->mName + ".Target");
|
||||
|
||||
// If there is no input position channel we will need
|
||||
// to supply the default position from the node's
|
||||
// local transformation matrix.
|
||||
/*TargetAnimationHelper helper;
|
||||
if (me->mAnim.akeyPositions.empty())
|
||||
{
|
||||
aiMatrix4x4& mat = (*i)->mTransform;
|
||||
helper.SetFixedMainAnimationChannel(aiVector3D(
|
||||
mat.a4, mat.b4, mat.c4));
|
||||
}
|
||||
else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
|
||||
helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
|
||||
|
||||
helper.Process(&me->mTargetAnim.akeyPositions);*/
|
||||
|
||||
// Allocate the key array and fill it
|
||||
nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
|
||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||
|
|
|
@ -304,7 +304,6 @@ void Parser::Parse() {
|
|||
}
|
||||
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -734,7 +733,6 @@ void Parser::ParseLV3MapBlock(Texture &map) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -859,7 +857,6 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) {
|
|||
}
|
||||
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -883,7 +880,6 @@ void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -1189,7 +1185,6 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("2", "*NODE_TM");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
|
||||
|
@ -1310,7 +1305,6 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("2", "*MESH");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
|
||||
|
@ -1344,7 +1338,6 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
|
||||
|
@ -1414,7 +1407,6 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshVertexListBlock(
|
||||
|
@ -1443,7 +1435,6 @@ void Parser::ParseLV3MeshVertexListBlock(
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
|
||||
|
@ -1470,7 +1461,6 @@ void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh)
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
|
||||
|
@ -1503,7 +1493,6 @@ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
|
||||
|
@ -1532,7 +1521,6 @@ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
|
||||
|
@ -1567,7 +1555,6 @@ void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) {
|
||||
|
@ -1595,7 +1582,6 @@ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh)
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
|
||||
|
@ -1623,7 +1609,6 @@ void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh)
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
|
||||
|
@ -1681,7 +1666,6 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||
|
|
|
@ -7,7 +7,7 @@ For details, see http://sourceforge.net/projects/libb64
|
|||
|
||||
#include "cencode.h" // changed from <B64/cencode.h>
|
||||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
static const int CHARS_PER_LINE = 72;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
|
|
|
@ -418,7 +418,6 @@ void B3DImporter::ReadTRIS(int v0) {
|
|||
ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
|
||||
#endif
|
||||
Fail("Bad triangle index");
|
||||
continue;
|
||||
}
|
||||
face->mNumIndices = 3;
|
||||
face->mIndices = new unsigned[3];
|
||||
|
|
|
@ -96,7 +96,8 @@ struct CustomDataTypeDescription {
|
|||
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
|
||||
* use a special readfunction for that cases
|
||||
*/
|
||||
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
|
||||
static std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { {
|
||||
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
|
||||
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
|
||||
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
|
||||
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
|
||||
|
|
|
@ -569,7 +569,7 @@ void Structure ::Convert<MVert>(
|
|||
const FileDatabase &db) const {
|
||||
|
||||
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_Warn>(dest.mat_nr,"mat_nr",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
|
||||
|
|
|
@ -1855,7 +1855,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
|||
default:
|
||||
// LineStrip is not supported due to expected index unmangling
|
||||
throw DeadlyImportError("Unsupported primitive type.");
|
||||
break;
|
||||
}
|
||||
|
||||
// store the face size to later reconstruct the face from
|
||||
|
|
|
@ -139,6 +139,7 @@ size_t Offset(const char* begin, const char* cursor) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, const char* begin, const char* cursor) AI_WONT_RETURN_SUFFIX;
|
||||
void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
@ -341,8 +342,7 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input,
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits)
|
||||
{
|
||||
bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
|
@ -408,7 +408,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while(Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
|
@ -431,8 +431,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||
{
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
|
||||
ai_assert(input);
|
||||
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
|
||||
|
||||
|
@ -465,7 +464,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
|||
try
|
||||
{
|
||||
while (cursor < end ) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
|
||||
if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -421,6 +421,8 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
|
|||
|
||||
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
||||
|
||||
// NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
|
||||
// All transformations to the camera will be handled by its node in the scenegraph.
|
||||
out_camera->mPosition = aiVector3D(0.0f);
|
||||
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
|
||||
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
|
||||
|
@ -640,7 +642,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
|
|||
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
|
||||
const PropertyTable &props = model.Props();
|
||||
|
||||
const auto zero_epsilon = ai_epsilon;
|
||||
const auto zero_epsilon = Math::getEpsilon<ai_real>();
|
||||
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
|
||||
const TransformationComp comp = static_cast<TransformationComp>(i);
|
||||
|
@ -873,8 +875,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
|
|||
data->Set(index++, prop.first, interpretedBool->Value());
|
||||
} else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
|
||||
data->Set(index++, prop.first, interpretedInt->Value());
|
||||
} else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedUInt->Value());
|
||||
} else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedUint64->Value());
|
||||
} else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedint64->Value());
|
||||
} else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
|
||||
data->Set(index++, prop.first, interpretedFloat->Value());
|
||||
} else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
|
||||
|
@ -1176,15 +1182,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
|
|||
std::vector<aiAnimMesh *> animMeshes;
|
||||
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
|
||||
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
|
||||
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (size_t i = 0; i < shapeGeometries.size(); i++) {
|
||||
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
|
||||
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
|
||||
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
|
||||
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
|
||||
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
|
||||
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
|
||||
const auto &curVertices = shapeGeometry->GetVertices();
|
||||
const auto &curNormals = shapeGeometry->GetNormals();
|
||||
const auto &curIndices = shapeGeometry->GetIndices();
|
||||
//losing channel name if using shapeGeometry->Name()
|
||||
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name()));
|
||||
// if blendShapeChannel Name is empty or don't have a ".", add geoMetryName;
|
||||
auto aniName = FixAnimMeshName(blendShapeChannel->Name());
|
||||
auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
|
||||
if (aniName.empty()) {
|
||||
aniName = geoMetryName;
|
||||
}
|
||||
else if (aniName.find('.') == aniName.npos) {
|
||||
aniName += "." + geoMetryName;
|
||||
}
|
||||
animMesh->mName.Set(aniName);
|
||||
for (size_t j = 0; j < curIndices.size(); j++) {
|
||||
const unsigned int curIndex = curIndices.at(j);
|
||||
aiVector3D vertex = curVertices.at(j);
|
||||
|
@ -1406,13 +1420,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
|||
std::vector<aiAnimMesh *> animMeshes;
|
||||
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
|
||||
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
|
||||
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (size_t i = 0; i < shapeGeometries.size(); i++) {
|
||||
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
|
||||
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
|
||||
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
|
||||
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
|
||||
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
|
||||
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
|
||||
const auto& curVertices = shapeGeometry->GetVertices();
|
||||
const auto& curNormals = shapeGeometry->GetNormals();
|
||||
const auto& curIndices = shapeGeometry->GetIndices();
|
||||
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
|
||||
for (size_t j = 0; j < curIndices.size(); j++) {
|
||||
unsigned int curIndex = curIndices.at(j);
|
||||
|
|
|
@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
|
|||
for (const Connection* con : conns) {
|
||||
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
auto pr = blendShapeChannels.insert(bspc);
|
||||
if (!pr.second) {
|
||||
FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,8 +181,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
|
|||
for (const Connection* con : conns) {
|
||||
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
auto pr = shapeGeometries.insert(sg);
|
||||
if (!pr.second) {
|
||||
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser& parser, const ImportSettings& settings) :
|
||||
Document::Document(Parser& parser, const ImportSettings& settings) :
|
||||
settings(settings), parser(parser) {
|
||||
ASSIMP_LOG_DEBUG("Creating FBX Document");
|
||||
|
||||
|
@ -265,13 +265,17 @@ Document::Document(const Parser& parser, const ImportSettings& settings) :
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document() {
|
||||
for(ObjectMap::value_type& v : objects) {
|
||||
delete v.second;
|
||||
Document::~Document()
|
||||
{
|
||||
// The document does not own the memory for the following objects, but we need to call their d'tor
|
||||
// so they can properly free memory like string members:
|
||||
|
||||
for (ObjectMap::value_type &v : objects) {
|
||||
delete_LazyObject(v.second);
|
||||
}
|
||||
|
||||
for(ConnectionMap::value_type& v : src_connections) {
|
||||
delete v.second;
|
||||
for (ConnectionMap::value_type &v : src_connections) {
|
||||
delete_Connection(v.second);
|
||||
}
|
||||
// |dest_connections| contain the same Connection objects as the |src_connections|
|
||||
}
|
||||
|
@ -356,9 +360,11 @@ void Document::ReadObjects() {
|
|||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, *eobjects, *this);
|
||||
objects[0] = new_LazyObject(0L, *eobjects, *this);
|
||||
|
||||
const Scope& sobjects = *eobjects->Compound();
|
||||
for(const ElementMap::value_type& el : sobjects.Elements()) {
|
||||
|
@ -387,7 +393,7 @@ void Document::ReadObjects() {
|
|||
delete foundObject->second;
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, *el.second, *this);
|
||||
objects[id] = new_LazyObject(id, *el.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if(!strcmp(el.first.c_str(),"AnimationStack")) {
|
||||
|
@ -454,8 +460,10 @@ void Document::ReadPropertyTemplates() {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections() {
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
void Document::ReadConnections()
|
||||
{
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
const Scope &sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
if(!econns || !econns->Compound()) {
|
||||
|
@ -494,7 +502,7 @@ void Document::ReadConnections() {
|
|||
}
|
||||
|
||||
// add new connection
|
||||
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
|
||||
const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
|
||||
src_connections.insert(ConnectionMap::value_type(src,c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest,c));
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_DOCUMENT_H
|
||||
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
#include <stdint.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include "FBXProperties.h"
|
||||
|
@ -80,6 +81,10 @@ class BlendShape;
|
|||
class Skin;
|
||||
class Cluster;
|
||||
|
||||
#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
|
||||
#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
|
||||
#define delete_LazyObject(_p) (_p)->~LazyObject()
|
||||
#define delete_Connection(_p) (_p)->~Connection()
|
||||
|
||||
/** Represents a delay-parsed FBX objects. Many objects in the scene
|
||||
* are not needed by assimp, so it makes no sense to parse them
|
||||
|
@ -855,14 +860,14 @@ public:
|
|||
return fullWeights;
|
||||
}
|
||||
|
||||
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const {
|
||||
const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
|
||||
return shapeGeometries;
|
||||
}
|
||||
|
||||
private:
|
||||
float percent;
|
||||
WeightArray fullWeights;
|
||||
std::vector<const ShapeGeometry*> shapeGeometries;
|
||||
std::unordered_set<const ShapeGeometry*> shapeGeometries;
|
||||
};
|
||||
|
||||
/** DOM class for BlendShape deformers */
|
||||
|
@ -872,12 +877,12 @@ public:
|
|||
|
||||
virtual ~BlendShape();
|
||||
|
||||
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const {
|
||||
const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
|
||||
return blendShapeChannels;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const BlendShapeChannel*> blendShapeChannels;
|
||||
std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
|
||||
};
|
||||
|
||||
/** DOM class for skin deformer clusters (aka sub-deformers) */
|
||||
|
@ -1072,7 +1077,7 @@ private:
|
|||
/** DOM root for a FBX file */
|
||||
class Document {
|
||||
public:
|
||||
Document(const Parser& parser, const ImportSettings& settings);
|
||||
Document(Parser& parser, const ImportSettings& settings);
|
||||
|
||||
~Document();
|
||||
|
||||
|
@ -1156,7 +1161,7 @@ private:
|
|||
const ImportSettings& settings;
|
||||
|
||||
ObjectMap objects;
|
||||
const Parser& parser;
|
||||
Parser& parser;
|
||||
|
||||
PropertyTemplateMap templates;
|
||||
ConnectionMap src_connections;
|
||||
|
|
|
@ -152,19 +152,19 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
// broad-phase tokenized pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
||||
Assimp::StackAllocator tempAllocator;
|
||||
try {
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens, begin, contents.size());
|
||||
TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
|
||||
} else {
|
||||
Tokenize(tokens, begin);
|
||||
Tokenize(tokens, begin, tempAllocator);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
Parser parser(tokens, tempAllocator, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser, mSettings);
|
||||
|
@ -183,10 +183,12 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
// assimp universal format (M)
|
||||
SetFileScale(size_relative_to_cm * 0.01f);
|
||||
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
throw;
|
||||
// This collection does not own the memory for the tokens, but we need to call their d'tor
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
|
||||
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,20 +138,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material() = default;
|
||||
|
||||
aiVector2D uvTrans;
|
||||
aiVector2D uvScaling;
|
||||
ai_real uvRotation;
|
||||
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
std::string fileName;
|
||||
std::string alphaSource;
|
||||
std::shared_ptr<const PropertyTable> props;
|
||||
|
||||
unsigned int crop[4]{};
|
||||
|
||||
const Video* media;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
|
||||
Object(id,element,name),
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
/// @param name The name instance
|
||||
/// @param doc The document instance
|
||||
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||
|
||||
|
||||
/// @brief The class destructor, default.
|
||||
virtual ~Geometry() = default;
|
||||
|
||||
|
@ -72,11 +72,12 @@ public:
|
|||
|
||||
/// @brief Get the BlendShape attached to this geometry or nullptr
|
||||
/// @return The blendshape arrays.
|
||||
const std::vector<const BlendShape*>& GetBlendShapes() const;
|
||||
const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
|
||||
|
||||
private:
|
||||
const Skin* skin;
|
||||
std::vector<const BlendShape*> blendShapes;
|
||||
std::unordered_set<const BlendShape*> blendShapes;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
@ -112,7 +113,7 @@ public:
|
|||
/// @return The binomal vector.
|
||||
const std::vector<aiVector3D>& GetBinormals() const;
|
||||
|
||||
/// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
|
||||
/// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
|
||||
/// Vertices are taken from the vertex data arrays in sequential order.
|
||||
/// @return The face indices vector.
|
||||
const std::vector<unsigned int>& GetFaceIndexCounts() const;
|
||||
|
|
|
@ -88,6 +88,7 @@ namespace {
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_WONT_RETURN void ParseError(const std::string& message, TokenPtr token) AI_WONT_RETURN_SUFFIX;
|
||||
void ParseError(const std::string& message, TokenPtr token)
|
||||
{
|
||||
if(token) {
|
||||
|
@ -115,8 +116,11 @@ namespace Assimp {
|
|||
namespace FBX {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
|
||||
Element::Element(const Token& key_token, Parser& parser) :
|
||||
key_token(key_token), compound(nullptr)
|
||||
{
|
||||
TokenPtr n = nullptr;
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
do {
|
||||
n = parser.AdvanceToNextToken();
|
||||
if(!n) {
|
||||
|
@ -145,7 +149,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
|
|||
}
|
||||
|
||||
if (n->Type() == TokenType_OPEN_BRACKET) {
|
||||
compound.reset(new Scope(parser));
|
||||
compound = new_Scope(parser);
|
||||
|
||||
// current token should be a TOK_CLOSE_BRACKET
|
||||
n = parser.CurrentToken();
|
||||
|
@ -163,6 +167,15 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
if (compound) {
|
||||
delete_Scope(compound);
|
||||
}
|
||||
|
||||
// no need to delete tokens, they are owned by the parser
|
||||
}
|
||||
|
||||
Scope::Scope(Parser& parser,bool topLevel)
|
||||
{
|
||||
if(!topLevel) {
|
||||
|
@ -172,6 +185,7 @@ Scope::Scope(Parser& parser,bool topLevel)
|
|||
}
|
||||
}
|
||||
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
TokenPtr n = parser.AdvanceToNextToken();
|
||||
if (n == nullptr) {
|
||||
ParseError("unexpected end of file");
|
||||
|
@ -188,36 +202,45 @@ Scope::Scope(Parser& parser,bool topLevel)
|
|||
ParseError("unexpected content: empty string.");
|
||||
}
|
||||
|
||||
elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
|
||||
auto *element = new_Element(*n, parser);
|
||||
|
||||
// Element() should stop at the next Key token (or right after a Close token)
|
||||
n = parser.CurrentToken();
|
||||
if (n == nullptr) {
|
||||
if (topLevel) {
|
||||
elements.insert(ElementMap::value_type(str, element));
|
||||
return;
|
||||
}
|
||||
delete element;
|
||||
ParseError("unexpected end of file",parser.LastToken());
|
||||
} else {
|
||||
elements.insert(ElementMap::value_type(str, element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Scope::~Scope() {
|
||||
for(ElementMap::value_type& v : elements) {
|
||||
delete v.second;
|
||||
Scope::~Scope()
|
||||
{
|
||||
// This collection does not own the memory for the elements, but we need to call their d'tor:
|
||||
|
||||
for (ElementMap::value_type &v : elements) {
|
||||
delete_Element(v.second);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parser::Parser (const TokenList& tokens, bool is_binary)
|
||||
: tokens(tokens)
|
||||
, last()
|
||||
, current()
|
||||
, cursor(tokens.begin())
|
||||
, is_binary(is_binary)
|
||||
Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
|
||||
tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("Parsing FBX tokens");
|
||||
root.reset(new Scope(*this,true));
|
||||
root = new_Scope(*this, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parser::~Parser()
|
||||
{
|
||||
delete_Scope(root);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/LogAux.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
#include "Common/StackAllocator.h"
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
|
@ -63,14 +64,14 @@ class Parser;
|
|||
class Element;
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef std::vector< Scope* > ScopeList;
|
||||
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
|
||||
|
||||
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
# define new_Scope new Scope
|
||||
# define new_Element new Element
|
||||
using ScopeList = std::vector<Scope*>;
|
||||
using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
|
||||
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
|
||||
|
||||
#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
|
||||
#define new_Element new (allocator.Allocate(sizeof(Element))) Element
|
||||
#define delete_Scope(_p) (_p)->~Scope()
|
||||
#define delete_Element(_p) (_p)->~Element()
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
|
@ -82,15 +83,16 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
|
|||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
* as their trailing member.
|
||||
**/
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Element(const Token& key_token, Parser& parser);
|
||||
~Element() = default;
|
||||
~Element();
|
||||
|
||||
const Scope* Compound() const {
|
||||
return compound.get();
|
||||
return compound;
|
||||
}
|
||||
|
||||
const Token& KeyToken() const {
|
||||
|
@ -104,7 +106,7 @@ public:
|
|||
private:
|
||||
const Token& key_token;
|
||||
TokenList tokens;
|
||||
std::unique_ptr<Scope> compound;
|
||||
Scope* compound;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
|
@ -159,8 +161,8 @@ class Parser
|
|||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser (const TokenList& tokens,bool is_binary);
|
||||
~Parser() = default;
|
||||
Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary);
|
||||
~Parser();
|
||||
|
||||
const Scope& GetRootScope() const {
|
||||
return *root;
|
||||
|
@ -170,6 +172,10 @@ public:
|
|||
return is_binary;
|
||||
}
|
||||
|
||||
StackAllocator &GetAllocator() {
|
||||
return allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
@ -180,10 +186,10 @@ private:
|
|||
|
||||
private:
|
||||
const TokenList& tokens;
|
||||
|
||||
StackAllocator &allocator;
|
||||
TokenPtr last, current;
|
||||
TokenList::const_iterator cursor;
|
||||
std::unique_ptr<Scope> root;
|
||||
Scope *root;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
|
|
@ -94,7 +94,8 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line,
|
|||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end,
|
||||
void ProcessDataToken(TokenList &output_tokens, StackAllocator &token_allocator,
|
||||
const char*& start, const char*& end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
|
@ -131,8 +132,7 @@ void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList& output_tokens, const char* input)
|
||||
{
|
||||
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
|
||||
ai_assert(input);
|
||||
ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
|
||||
|
||||
|
@ -164,7 +164,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
in_double_quotes = false;
|
||||
token_end = cur;
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
pending_data_token = false;
|
||||
}
|
||||
continue;
|
||||
|
@ -181,30 +181,30 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
continue;
|
||||
|
||||
case ';':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
comment = true;
|
||||
continue;
|
||||
|
||||
case '{':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end, line, column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case ',':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
|
||||
}
|
||||
else {
|
||||
TokenizeError("unexpected colon", line, column);
|
||||
|
@ -226,7 +226,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
}
|
||||
}
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,type);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
|
||||
}
|
||||
|
||||
pending_data_token = false;
|
||||
|
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "Common/StackAllocator.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/defs.h>
|
||||
#include <vector>
|
||||
|
@ -157,7 +158,8 @@ private:
|
|||
typedef const Token* TokenPtr;
|
||||
typedef std::vector< TokenPtr > TokenList;
|
||||
|
||||
#define new_Token new Token
|
||||
#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
|
||||
#define delete_Token(_p) (_p)->~Token()
|
||||
|
||||
|
||||
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
|
||||
|
@ -167,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList;
|
|||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void Tokenize(TokenList& output_tokens, const char* input);
|
||||
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &tokenAllocator);
|
||||
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
|
@ -178,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
|
|||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &tokenAllocator);
|
||||
|
||||
|
||||
} // ! FBX
|
||||
|
|
|
@ -66,6 +66,17 @@ struct delete_fun
|
|||
}
|
||||
};
|
||||
|
||||
/** helper for std::for_each to call the destructor on all items in a container without freeing their heap*/
|
||||
template <typename T>
|
||||
struct destructor_fun {
|
||||
void operator()(const volatile T* del) {
|
||||
if (del) {
|
||||
del->~T();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Get a string representation for a #TokenType. */
|
||||
const char* TokenTypeString(TokenType t);
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Import a HMP4 file
|
||||
*/
|
||||
void InternReadFile_HMP4();
|
||||
AI_WONT_RETURN void InternReadFile_HMP4() AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Import a HMP5 file
|
||||
|
|
|
@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "AssetLib/IFC/IFCUtil.h"
|
||||
#include "Common/PolyTools.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
@ -235,7 +236,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
|
|||
struct CompareVector {
|
||||
bool operator () (const IfcVector3& a, const IfcVector3& b) const {
|
||||
IfcVector3 d = a - b;
|
||||
IfcFloat eps = ai_epsilon;
|
||||
constexpr IfcFloat eps = ai_epsilon;
|
||||
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -65,7 +65,6 @@ void LWOImporter::LoadLWOBFile()
|
|||
if (mFileBuffer + head.length > end)
|
||||
{
|
||||
throw DeadlyImportError("LWOB: Invalid chunk length");
|
||||
break;
|
||||
}
|
||||
uint8_t* const next = mFileBuffer+head.length;
|
||||
switch (head.type)
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -51,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "AssetLib/LWO/LWOLoader.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
|
||||
#include <assimp/ByteSwapper.h>
|
||||
#include <assimp/SGSpatialSort.h>
|
||||
|
@ -178,7 +177,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
mLayers->push_back(Layer());
|
||||
mCurLayer = &mLayers->back();
|
||||
mCurLayer->mName = "<LWODefault>";
|
||||
mCurLayer->mIndex = (uint16_t) -1;
|
||||
mCurLayer->mIndex = 1;
|
||||
|
||||
// old lightwave file format (prior to v6)
|
||||
mIsLWO2 = false;
|
||||
|
@ -398,14 +397,6 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
pvVC[w]++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// process vertex weights. We can't properly reconstruct the whole skeleton for now,
|
||||
// but we can create dummy bones for all weight channels which we have.
|
||||
for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
face.mIndices[q] = vert;
|
||||
}
|
||||
pf->mIndices = face.mIndices;
|
||||
|
@ -429,7 +420,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
// Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
|
||||
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
|
||||
if (layer.mName != "<LWODefault>" || num > 0) {
|
||||
aiNode *pcNode = new aiNode();
|
||||
std::unique_ptr<aiNode> pcNode(new aiNode());
|
||||
pcNode->mName.Set(layer.mName);
|
||||
pcNode->mParent = (aiNode *)&layer;
|
||||
pcNode->mNumMeshes = num;
|
||||
|
@ -439,7 +430,8 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p)
|
||||
pcNode->mMeshes[p] = p + meshStart;
|
||||
}
|
||||
apcNodes[layer.mIndex] = pcNode;
|
||||
ASSIMP_LOG_DEBUG("insert apcNode for layer ", layer.mIndex, " \"", layer.mName, "\"");
|
||||
apcNodes[layer.mIndex] = pcNode.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,7 +527,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
continue;
|
||||
vNormals += v;
|
||||
}
|
||||
mesh->mNormals[idx] = vNormals.Normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +547,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
const aiVector3D &v = faceNormals[*a];
|
||||
vNormals += v;
|
||||
}
|
||||
vNormals.Normalize();
|
||||
for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
|
||||
mesh->mNormals[*a] = vNormals;
|
||||
vertexDone[*a] = true;
|
||||
|
@ -564,6 +554,7 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
}
|
||||
}
|
||||
}
|
||||
GeometryUtils::normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -572,40 +563,64 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
|
|||
aiNode *root = mScene->mRootNode = new aiNode();
|
||||
root->mName.Set("<LWORoot>");
|
||||
|
||||
//Set parent of all children, inserting pivots
|
||||
std::map<uint16_t, aiNode *> mapPivot;
|
||||
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||
|
||||
//Get the parent index
|
||||
LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent);
|
||||
uint16_t parentIndex = nodeLayer->mParent;
|
||||
|
||||
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
||||
aiNode *pivotNode = new aiNode();
|
||||
pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
|
||||
itapcNodes->second->mParent = pivotNode;
|
||||
|
||||
//Look for the parent node to attach the pivot to
|
||||
if (apcNodes.find(parentIndex) != apcNodes.end()) {
|
||||
pivotNode->mParent = apcNodes[parentIndex];
|
||||
} else {
|
||||
//If not, attach to the root node
|
||||
pivotNode->mParent = root;
|
||||
}
|
||||
|
||||
//Set the node and the pivot node transformation
|
||||
itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
|
||||
itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
|
||||
itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
|
||||
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
||||
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
||||
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
||||
mapPivot[-(itapcNodes->first + 2)] = pivotNode;
|
||||
ASSIMP_LOG_DEBUG("apcNodes initial size: ", apcNodes.size());
|
||||
if (!apcNodes.empty()) {
|
||||
ASSIMP_LOG_DEBUG("first apcNode is: ", apcNodes.begin()->first, " \"", apcNodes.begin()->second->mName.C_Str(), "\"");
|
||||
}
|
||||
|
||||
//Merge pivot map into node map
|
||||
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
||||
apcNodes[itMapPivot->first] = itMapPivot->second;
|
||||
//Set parent of all children, inserting pivots
|
||||
{
|
||||
std::map<uint16_t, aiNode *> mapPivot;
|
||||
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||
|
||||
//Get the parent index
|
||||
LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent);
|
||||
uint16_t parentIndex = nodeLayer->mParent;
|
||||
|
||||
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
||||
std::unique_ptr<aiNode> pivotNode(new aiNode());
|
||||
pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
|
||||
itapcNodes->second->mParent = pivotNode.get();
|
||||
|
||||
//Look for the parent node to attach the pivot to
|
||||
if (apcNodes.find(parentIndex) != apcNodes.end()) {
|
||||
pivotNode->mParent = apcNodes[parentIndex];
|
||||
} else {
|
||||
//If not, attach to the root node
|
||||
pivotNode->mParent = root;
|
||||
}
|
||||
|
||||
//Set the node and the pivot node transformation
|
||||
itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
|
||||
itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
|
||||
itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
|
||||
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
||||
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
||||
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
||||
uint16_t pivotNodeId = static_cast<uint16_t>(-(itapcNodes->first + 2));
|
||||
ASSIMP_LOG_DEBUG("insert pivot node: ", pivotNodeId);
|
||||
auto oldNodeIt = mapPivot.find(pivotNodeId);
|
||||
if (oldNodeIt != mapPivot.end()) {
|
||||
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in pivot map ", pivotNodeId, " \"", pivotNode->mName.C_Str(), "\"");
|
||||
} else {
|
||||
mapPivot.emplace(pivotNodeId, pivotNode.release());
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG("pivot nodes: ", mapPivot.size());
|
||||
//Merge pivot map into node map
|
||||
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end();) {
|
||||
uint16_t pivotNodeId = itMapPivot->first;
|
||||
auto oldApcNodeIt = apcNodes.find(pivotNodeId);
|
||||
if (oldApcNodeIt != apcNodes.end()) {
|
||||
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in apc nodes ", pivotNodeId, " \"", itMapPivot->second->mName.C_Str(), "\"");
|
||||
} else {
|
||||
apcNodes.emplace(pivotNodeId, itMapPivot->second);
|
||||
}
|
||||
itMapPivot->second = nullptr;
|
||||
itMapPivot = mapPivot.erase(itMapPivot);
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("total nodes: ", apcNodes.size());
|
||||
}
|
||||
|
||||
//Set children of all parents
|
||||
|
@ -627,8 +642,15 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!mScene->mRootNode->mNumChildren)
|
||||
if (!mScene->mRootNode->mNumChildren) {
|
||||
ASSIMP_LOG_DEBUG("All apcNodes:");
|
||||
for (auto nodeIt = apcNodes.begin(); nodeIt != apcNodes.end(); ) {
|
||||
ASSIMP_LOG_DEBUG("Node ", nodeIt->first, " \"", nodeIt->second->mName.C_Str(), "\"");
|
||||
nodeIt->second = nullptr;
|
||||
nodeIt = apcNodes.erase(nodeIt);
|
||||
}
|
||||
throw DeadlyImportError("LWO: Unable to build a valid node graph");
|
||||
}
|
||||
|
||||
// Remove a single root node with no meshes assigned to it ...
|
||||
if (1 == mScene->mRootNode->mNumChildren) {
|
||||
|
@ -1462,7 +1484,6 @@ void LWOImporter::LoadLWO2File() {
|
|||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO2: Chunk length points behind the file");
|
||||
break;
|
||||
}
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
|
|
|
@ -345,7 +345,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
|
|||
|
||||
// (the diffuse value is just a scaling factor)
|
||||
// If a diffuse texture is set, we set this value to 1.0
|
||||
clr = (b && false ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
|
||||
clr = (b ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
|
||||
clr.r *= surf.mDiffuseValue;
|
||||
clr.g *= surf.mDiffuseValue;
|
||||
clr.b *= surf.mDiffuseValue;
|
||||
|
|
|
@ -365,9 +365,7 @@ public:
|
|||
static void ReportWarning (const char* warn, unsigned int line);
|
||||
|
||||
|
||||
void ReportError (const char* error) {
|
||||
return ReportError(error, lineNumber);
|
||||
}
|
||||
AI_WONT_RETURN void ReportError (const char* error) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
void ReportWarning (const char* warn) {
|
||||
return ReportWarning(warn, lineNumber);
|
||||
|
@ -404,6 +402,9 @@ private:
|
|||
unsigned int lineNumber;
|
||||
};
|
||||
|
||||
inline void MD5Parser::ReportError(const char* error) {
|
||||
ReportError(error, lineNumber);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool MD5Parser::SkipLine(const char* in, const char** out) {
|
||||
++lineNumber;
|
||||
|
|
|
@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() {
|
|||
|
||||
temp_bones_.resize(header_->numbones);
|
||||
|
||||
// Create the main 'bones' node that will contain all MDL root bones.
|
||||
aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
|
||||
rootnode_children_.push_back(bones_node);
|
||||
bones_node->mNumChildren = static_cast<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.
|
||||
for (int i = 0; i < header_->numbones; ++i) {
|
||||
aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]);
|
||||
aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
|
||||
|
||||
aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
|
||||
temp_bones_[i].absolute_transform = bone_node->mTransformation =
|
||||
|
@ -485,9 +487,11 @@ void HL1MDLLoader::read_bones() {
|
|||
aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
|
||||
|
||||
if (pbone[i].parent == -1) {
|
||||
bone_node->mParent = scene_->mRootNode;
|
||||
bone_node->mParent = bones_node;
|
||||
roots.push_back(i); // This bone has no parent. Add it to the roots list.
|
||||
} else {
|
||||
bone_node->mParent = bones_node->mChildren[pbone[i].parent];
|
||||
bone_node->mParent = temp_bones_[pbone[i].parent].node;
|
||||
temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
|
||||
|
||||
temp_bones_[i].absolute_transform =
|
||||
temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
|
||||
|
@ -496,6 +500,36 @@ void HL1MDLLoader::read_bones() {
|
|||
temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
|
||||
temp_bones_[i].offset_matrix.Inverse();
|
||||
}
|
||||
|
||||
// Allocate memory for each MDL root bone.
|
||||
bones_node->mNumChildren = static_cast<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);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -143,6 +143,14 @@ private:
|
|||
*/
|
||||
static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
|
||||
|
||||
/**
|
||||
* \brief Build a bone's node children hierarchy.
|
||||
*
|
||||
* \param[in] bone The bone for which we must build all children hierarchy.
|
||||
*/
|
||||
struct TempBone;
|
||||
void build_bone_children_hierarchy(const TempBone& bone);
|
||||
|
||||
/** Output scene to be filled */
|
||||
aiScene *scene_;
|
||||
|
||||
|
@ -198,11 +206,13 @@ private:
|
|||
TempBone() :
|
||||
node(nullptr),
|
||||
absolute_transform(),
|
||||
offset_matrix() {}
|
||||
offset_matrix(),
|
||||
children() {}
|
||||
|
||||
aiNode *node;
|
||||
aiMatrix4x4 absolute_transform;
|
||||
aiMatrix4x4 offset_matrix;
|
||||
std::vector<int> children; // Bone children
|
||||
};
|
||||
|
||||
std::vector<TempBone> temp_bones_;
|
||||
|
|
|
@ -139,7 +139,7 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Import a CS:S/HL2 MDL file (not fully implemented)
|
||||
*/
|
||||
void InternReadFile_HL2( );
|
||||
AI_WONT_RETURN void InternReadFile_HL2( ) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Check whether a given position is inside the valid range
|
||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <assimp/types.h>
|
||||
#include "MMDCpp14.h"
|
||||
|
||||
namespace pmx
|
||||
|
@ -730,7 +731,7 @@ namespace pmx
|
|||
std::unique_ptr<PmxAncherRigidBody []> anchers;
|
||||
int pin_vertex_count;
|
||||
std::unique_ptr<int []> pin_vertices;
|
||||
void Read(std::istream *stream, PmxSetting *setting);
|
||||
AI_WONT_RETURN void Read(std::istream *stream, PmxSetting *setting) AI_WONT_RETURN_SUFFIX;
|
||||
};
|
||||
|
||||
class PmxModel
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
Copyright (c) 2006-2023, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
@ -84,7 +84,6 @@ ObjFileImporter::ObjFileImporter() :
|
|||
// Destructor.
|
||||
ObjFileImporter::~ObjFileImporter() {
|
||||
delete m_pRootObject;
|
||||
m_pRootObject = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -270,7 +269,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
|
|||
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
|
||||
unsigned int meshId = pObject->m_Meshes[i];
|
||||
aiMesh *pMesh = createTopology(pModel, pObject, meshId);
|
||||
if (pMesh) {
|
||||
if (pMesh != nullptr) {
|
||||
if (pMesh->mNumFaces > 0) {
|
||||
MeshArray.push_back(pMesh);
|
||||
} else {
|
||||
|
@ -324,14 +323,13 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<aiMesh> pMesh(new aiMesh);
|
||||
aiMesh *pMesh = new aiMesh;
|
||||
if (!pObjMesh->m_name.empty()) {
|
||||
pMesh->mName.Set(pObjMesh->m_name);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
|
||||
const ObjFile::Face *inp = pObjMesh->m_Faces[index];
|
||||
//ai_assert(nullptr != inp);
|
||||
|
||||
if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
|
||||
pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
|
||||
|
@ -387,9 +385,9 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
|
|||
}
|
||||
|
||||
// Create mesh vertices
|
||||
createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
|
||||
createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount);
|
||||
|
||||
return pMesh.release();
|
||||
return pMesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -236,7 +236,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name == "cstype";
|
||||
goto pf_skip_line;
|
||||
} break;
|
||||
}
|
||||
|
||||
default: {
|
||||
pf_skip_line:
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Assimp {
|
|||
namespace Ogre {
|
||||
|
||||
//AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
|
||||
if (!error.empty()) {
|
||||
throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'");
|
||||
|
@ -128,7 +128,6 @@ bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name)
|
|||
}
|
||||
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mesh XML constants
|
||||
|
@ -490,7 +489,7 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
|
|||
OgreXmlSerializer serializer(xmlParser.get());
|
||||
XmlNode root = xmlParser->getRootNode();
|
||||
if (std::string(root.name()) != nnSkeleton) {
|
||||
printf("\nSkeleton is not a valid root: %s\n", root.name());
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("nSkeleton is not a valid root: ", root.name(), ".");
|
||||
for (auto &a : root.children()) {
|
||||
if (std::string(a.name()) == nnSkeleton) {
|
||||
root = a;
|
||||
|
|
|
@ -460,14 +460,12 @@ void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
|
|||
void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == m_currentNode) {
|
||||
throw DeadlyImportError("No current node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
Value *val(node->getValue());
|
||||
if (nullptr != val) {
|
||||
if (Value::ValueType::ddl_string != val->m_type) {
|
||||
throw DeadlyImportError("OpenGEX: invalid data type for value in node name.");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string name(val->getString());
|
||||
|
@ -508,7 +506,6 @@ static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
|
|||
void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == m_currentNode) {
|
||||
throw DeadlyImportError("No parent node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> objRefNames;
|
||||
|
@ -532,7 +529,6 @@ void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
|
|||
void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == m_currentNode) {
|
||||
throw DeadlyImportError("No parent node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> matRefNames;
|
||||
|
@ -672,14 +668,12 @@ static void setMatrix(aiNode *node, DataArrayList *transformData) {
|
|||
void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == m_currentNode) {
|
||||
throw DeadlyImportError("No parent node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
DataArrayList *transformData(node->getDataArrayList());
|
||||
if (nullptr != transformData) {
|
||||
if (transformData->m_numItems != 16) {
|
||||
throw DeadlyImportError("Invalid number of data for transform matrix.");
|
||||
return;
|
||||
}
|
||||
setMatrix(m_currentNode, transformData);
|
||||
}
|
||||
|
@ -835,7 +829,6 @@ static void copyColor4DArray(size_t numItems, DataArrayList *vaList, aiColor4D *
|
|||
void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == node) {
|
||||
throw DeadlyImportError("No parent node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
Property *prop = node->getProperties();
|
||||
|
@ -876,12 +869,10 @@ void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene *
|
|||
void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
|
||||
if (nullptr == node) {
|
||||
throw DeadlyImportError("No parent node for name.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nullptr == m_currentMesh) {
|
||||
throw DeadlyImportError("No current mesh for index data found.");
|
||||
return;
|
||||
}
|
||||
|
||||
DataArrayList *vaList = node->getDataArrayList();
|
||||
|
|
|
@ -382,11 +382,10 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
|
|||
|
||||
// TODO
|
||||
goto outer;
|
||||
} break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw DeadlyImportError("Quick3D: Unknown chunk");
|
||||
break;
|
||||
};
|
||||
}
|
||||
outer:
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Assimp {
|
|||
class RAWImporter : public BaseImporter {
|
||||
public:
|
||||
RAWImporter();
|
||||
~RAWImporter();
|
||||
~RAWImporter() override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
|
|
|
@ -85,7 +85,7 @@ static const aiImporterDesc desc = {
|
|||
struct SIBChunk {
|
||||
uint32_t Tag;
|
||||
uint32_t Size;
|
||||
} PACK_STRUCT;
|
||||
};
|
||||
|
||||
enum {
|
||||
POS,
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Assimp {
|
|||
class UnrealImporter : public BaseImporter {
|
||||
public:
|
||||
UnrealImporter();
|
||||
~UnrealImporter();
|
||||
~UnrealImporter() override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Returns whether we can handle the format of the given file
|
||||
|
|
|
@ -578,7 +578,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
|
|||
aiString name;
|
||||
pScene->mMaterials[b]->Get( AI_MATKEY_NAME, name);
|
||||
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
|
||||
oldMat.sceneIndex = a;
|
||||
oldMat.sceneIndex = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -839,7 +839,6 @@ void XFileParser::ParseDataObjectAnimationKey(AnimBone *pAnimBone) {
|
|||
|
||||
default:
|
||||
ThrowException("Unknown key type ", keyType, " in animation.");
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
// key separator
|
||||
|
|
|
@ -58,8 +58,6 @@ class X3DExporter {
|
|||
Value(value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
SAttribute(SAttribute &&rhs) AI_NO_EXCEPT = default;
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
|
|
|
@ -55,6 +55,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <string>
|
||||
|
||||
namespace Assimp {
|
||||
AI_WONT_RETURN inline void Throw_ArgOutOfRange(const std::string &argument) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_CloseNotFound(const std::string &node) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrF(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrD(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrB(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrI(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_DEF_And_USE(const std::string &nodeName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_TagCountIncorrect(const std::string &pNode) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN inline void Throw_USE_NotFound(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
inline void Throw_ArgOutOfRange(const std::string &argument) {
|
||||
throw DeadlyImportError("Argument value is out of range for: \"" + argument + "\".");
|
||||
|
|
|
@ -12,7 +12,6 @@ bool X3DXmlHelper::getColor3DAttribute(XmlNode &node, const char *attributeName,
|
|||
tokenize<std::string>(val, values, " ");
|
||||
if (values.size() != 3) {
|
||||
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||
return false;
|
||||
}
|
||||
auto it = values.begin();
|
||||
color.r = stof(*it++);
|
||||
|
@ -30,7 +29,6 @@ bool X3DXmlHelper::getVector2DAttribute(XmlNode &node, const char *attributeName
|
|||
tokenize<std::string>(val, values, " ");
|
||||
if (values.size() != 2) {
|
||||
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||
return false;
|
||||
}
|
||||
auto it = values.begin();
|
||||
color.x = stof(*it++);
|
||||
|
@ -47,7 +45,6 @@ bool X3DXmlHelper::getVector3DAttribute(XmlNode &node, const char *attributeName
|
|||
tokenize<std::string>(val, values, " ");
|
||||
if (values.size() != 3) {
|
||||
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
|
||||
return false;
|
||||
}
|
||||
auto it = values.begin();
|
||||
color.x = stof(*it++);
|
||||
|
|
|
@ -513,21 +513,22 @@ struct Camera : public Object {
|
|||
};
|
||||
|
||||
Type type;
|
||||
struct Perspective {
|
||||
float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
|
||||
float yfov; //!<The floating - point vertical field of view in radians. (required)
|
||||
float zfar; //!<The floating - point distance to the far clipping plane. (required)
|
||||
float znear; //!< The floating - point distance to the near clipping plane. (required)
|
||||
};
|
||||
|
||||
struct Ortographic {
|
||||
float xmag; //! The floating-point horizontal magnification of the view. (required)
|
||||
float ymag; //! The floating-point vertical magnification of the view. (required)
|
||||
float zfar; //! The floating-point distance to the far clipping plane. (required)
|
||||
float znear; //! The floating-point distance to the near clipping plane. (required)
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
|
||||
float yfov; //!<The floating - point vertical field of view in radians. (required)
|
||||
float zfar; //!<The floating - point distance to the far clipping plane. (required)
|
||||
float znear; //!< The floating - point distance to the near clipping plane. (required)
|
||||
} perspective;
|
||||
|
||||
struct {
|
||||
float xmag; //! The floating-point horizontal magnification of the view. (required)
|
||||
float ymag; //! The floating-point vertical magnification of the view. (required)
|
||||
float zfar; //! The floating-point distance to the far clipping plane. (required)
|
||||
float znear; //! The floating-point distance to the near clipping plane. (required)
|
||||
} ortographic;
|
||||
struct Perspective perspective;
|
||||
struct Ortographic ortographic;
|
||||
};
|
||||
|
||||
Camera() = default;
|
||||
|
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_materials_pbrSpecularGlossiness full
|
||||
* KHR_materials_specular full
|
||||
* KHR_materials_unlit full
|
||||
* KHR_lights_punctual full
|
||||
* KHR_materials_sheen full
|
||||
|
@ -483,7 +484,7 @@ private:
|
|||
|
||||
public:
|
||||
Buffer();
|
||||
~Buffer();
|
||||
~Buffer() override;
|
||||
|
||||
void Read(Value &obj, Asset &r);
|
||||
|
||||
|
@ -565,7 +566,7 @@ struct Accessor : public Object {
|
|||
inline size_t GetMaxByteSize();
|
||||
|
||||
template <class T>
|
||||
void ExtractData(T *&outData);
|
||||
size_t ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices = nullptr);
|
||||
|
||||
void WriteData(size_t count, const void *src_buffer, size_t src_stride);
|
||||
void WriteSparseValues(size_t count, const void *src_data, size_t src_dataStride);
|
||||
|
@ -710,6 +711,7 @@ const vec4 defaultBaseColor = { 1, 1, 1, 1 };
|
|||
const vec3 defaultEmissiveFactor = { 0, 0, 0 };
|
||||
const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 };
|
||||
const vec3 defaultSpecularFactor = { 1, 1, 1 };
|
||||
const vec3 defaultSpecularColorFactor = { 0, 0, 0 };
|
||||
const vec3 defaultSheenFactor = { 0, 0, 0 };
|
||||
const vec3 defaultAttenuationColor = { 1, 1, 1 };
|
||||
|
||||
|
@ -753,6 +755,16 @@ struct PbrSpecularGlossiness {
|
|||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct MaterialSpecular {
|
||||
float specularFactor;
|
||||
vec3 specularColorFactor;
|
||||
TextureInfo specularTexture;
|
||||
TextureInfo specularColorTexture;
|
||||
|
||||
MaterialSpecular() { SetDefaults(); }
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct MaterialSheen {
|
||||
vec3 sheenColorFactor;
|
||||
float sheenRoughnessFactor;
|
||||
|
@ -817,6 +829,9 @@ struct Material : public Object {
|
|||
//extension: KHR_materials_pbrSpecularGlossiness
|
||||
Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
|
||||
|
||||
//extension: KHR_materials_specular
|
||||
Nullable<MaterialSpecular> materialSpecular;
|
||||
|
||||
//extension: KHR_materials_sheen
|
||||
Nullable<MaterialSheen> materialSheen;
|
||||
|
||||
|
@ -1099,6 +1114,7 @@ public:
|
|||
//! Keeps info about the enabled extensions
|
||||
struct Extensions {
|
||||
bool KHR_materials_pbrSpecularGlossiness;
|
||||
bool KHR_materials_specular;
|
||||
bool KHR_materials_unlit;
|
||||
bool KHR_lights_punctual;
|
||||
bool KHR_texture_transform;
|
||||
|
@ -1113,13 +1129,14 @@ public:
|
|||
bool KHR_texture_basisu;
|
||||
|
||||
Extensions() :
|
||||
KHR_materials_pbrSpecularGlossiness(false),
|
||||
KHR_materials_unlit(false),
|
||||
KHR_lights_punctual(false),
|
||||
KHR_texture_transform(false),
|
||||
KHR_materials_sheen(false),
|
||||
KHR_materials_clearcoat(false),
|
||||
KHR_materials_transmission(false),
|
||||
KHR_materials_pbrSpecularGlossiness(false),
|
||||
KHR_materials_specular(false),
|
||||
KHR_materials_unlit(false),
|
||||
KHR_lights_punctual(false),
|
||||
KHR_texture_transform(false),
|
||||
KHR_materials_sheen(false),
|
||||
KHR_materials_clearcoat(false),
|
||||
KHR_materials_transmission(false),
|
||||
KHR_materials_volume(false),
|
||||
KHR_materials_ior(false),
|
||||
KHR_materials_emissive_strength(false),
|
||||
|
|
|
@ -962,14 +962,15 @@ inline size_t Accessor::GetMaxByteSize() {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
void Accessor::ExtractData(T *&outData) {
|
||||
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
|
||||
uint8_t *data = GetPointer();
|
||||
if (!data) {
|
||||
throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
|
||||
const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
|
||||
const size_t elemSize = GetElementSize();
|
||||
const size_t totalSize = elemSize * count;
|
||||
const size_t totalSize = elemSize * usedCount;
|
||||
|
||||
const size_t stride = GetStride();
|
||||
|
||||
|
@ -980,18 +981,31 @@ void Accessor::ExtractData(T *&outData) {
|
|||
}
|
||||
|
||||
const size_t maxSize = GetMaxByteSize();
|
||||
if (count * stride > maxSize) {
|
||||
throw DeadlyImportError("GLTF: count*stride ", (count * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
|
||||
outData = new T[count];
|
||||
if (stride == elemSize && targetElemSize == elemSize) {
|
||||
memcpy(outData, data, totalSize);
|
||||
} else {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
memcpy(outData + i, data + i * stride, elemSize);
|
||||
outData = new T[usedCount];
|
||||
|
||||
if (remappingIndices != nullptr) {
|
||||
const unsigned int maxIndex = static_cast<unsigned int>(maxSize / stride - 1);
|
||||
for (size_t i = 0; i < usedCount; ++i) {
|
||||
size_t srcIdx = (*remappingIndices)[i];
|
||||
if (srcIdx > maxIndex) {
|
||||
throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
memcpy(outData + i, data + srcIdx * stride, elemSize);
|
||||
}
|
||||
} else { // non-indexed cases
|
||||
if (usedCount * stride > maxSize) {
|
||||
throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
if (stride == elemSize && targetElemSize == elemSize) {
|
||||
memcpy(outData, data, totalSize);
|
||||
} else {
|
||||
for (size_t i = 0; i < usedCount; ++i) {
|
||||
memcpy(outData + i, data + i * stride, elemSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedCount;
|
||||
}
|
||||
|
||||
inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) {
|
||||
|
@ -1249,6 +1263,19 @@ inline void Material::Read(Value &material, Asset &r) {
|
|||
this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
|
||||
}
|
||||
}
|
||||
|
||||
if (r.extensionsUsed.KHR_materials_specular) {
|
||||
if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) {
|
||||
MaterialSpecular specular;
|
||||
|
||||
ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor);
|
||||
ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture);
|
||||
ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor);
|
||||
ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture);
|
||||
|
||||
this->materialSpecular = Nullable<MaterialSpecular>(specular);
|
||||
}
|
||||
}
|
||||
|
||||
// Extension KHR_texture_transform is handled in ReadTextureProperty
|
||||
|
||||
|
@ -1347,6 +1374,12 @@ inline void PbrSpecularGlossiness::SetDefaults() {
|
|||
glossinessFactor = 1.0f;
|
||||
}
|
||||
|
||||
inline void MaterialSpecular::SetDefaults() {
|
||||
//KHR_materials_specular properties
|
||||
SetVector(specularColorFactor, defaultSpecularColorFactor);
|
||||
specularFactor = 0.f;
|
||||
}
|
||||
|
||||
inline void MaterialSheen::SetDefaults() {
|
||||
//KHR_materials_sheen properties
|
||||
SetVector(sheenColorFactor, defaultSheenFactor);
|
||||
|
@ -2033,6 +2066,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
|
|||
}
|
||||
|
||||
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
|
||||
CHECK_EXT(KHR_materials_specular);
|
||||
CHECK_EXT(KHR_materials_unlit);
|
||||
CHECK_EXT(KHR_lights_punctual);
|
||||
CHECK_EXT(KHR_texture_transform);
|
||||
|
|
|
@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_materials_pbrSpecularGlossiness: full
|
||||
* KHR_materials_specular: full
|
||||
* KHR_materials_unlit: full
|
||||
* KHR_materials_sheen: full
|
||||
* KHR_materials_clearcoat: full
|
||||
|
|
|
@ -418,6 +418,26 @@ namespace glTF2 {
|
|||
exts.AddMember("KHR_materials_unlit", unlit, w.mAl);
|
||||
}
|
||||
|
||||
if (m.materialSpecular.isPresent) {
|
||||
Value materialSpecular(rapidjson::Type::kObjectType);
|
||||
materialSpecular.SetObject();
|
||||
|
||||
MaterialSpecular &specular = m.materialSpecular.value;
|
||||
|
||||
if (specular.specularFactor != 0.0f) {
|
||||
WriteFloat(materialSpecular, specular.specularFactor, "specularFactor", w.mAl);
|
||||
WriteTex(materialSpecular, specular.specularTexture, "specularTexture", w.mAl);
|
||||
}
|
||||
if (specular.specularColorFactor[0] != defaultSpecularColorFactor[0] && specular.specularColorFactor[1] != defaultSpecularColorFactor[1] && specular.specularColorFactor[2] != defaultSpecularColorFactor[2]) {
|
||||
WriteVec(materialSpecular, specular.specularColorFactor, "specularColorFactor", w.mAl);
|
||||
WriteTex(materialSpecular, specular.specularColorTexture, "specularColorTexture", w.mAl);
|
||||
}
|
||||
|
||||
if (!materialSpecular.ObjectEmpty()) {
|
||||
exts.AddMember("KHR_materials_specular", materialSpecular, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (m.materialSheen.isPresent) {
|
||||
Value materialSheen(rapidjson::Type::kObjectType);
|
||||
|
||||
|
@ -550,7 +570,7 @@ namespace glTF2 {
|
|||
|
||||
inline void Write(Value& obj, Mesh& m, AssetWriter& w)
|
||||
{
|
||||
/****************** Primitives *******************/
|
||||
/****************** Primitives *******************/
|
||||
Value primitives;
|
||||
primitives.SetArray();
|
||||
primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
|
||||
|
@ -929,6 +949,10 @@ namespace glTF2 {
|
|||
exts.PushBack(StringRef("KHR_materials_unlit"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_specular) {
|
||||
exts.PushBack(StringRef("KHR_materials_specular"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_sheen) {
|
||||
exts.PushBack(StringRef("KHR_materials_sheen"), mAl);
|
||||
}
|
||||
|
@ -980,7 +1004,7 @@ namespace glTF2 {
|
|||
if (d.mObjs.empty()) return;
|
||||
|
||||
Value* container = &mDoc;
|
||||
const char* context = "Document";
|
||||
const char* context = "Document";
|
||||
|
||||
if (d.mExtId) {
|
||||
Value* exts = FindObject(mDoc, "extensions");
|
||||
|
|
|
@ -640,11 +640,10 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial &mat, vec3 &prop, const cha
|
|||
return result;
|
||||
}
|
||||
|
||||
// This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default.
|
||||
bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) {
|
||||
bool result = false;
|
||||
// If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension
|
||||
// NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular
|
||||
|
||||
if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) {
|
||||
result = true;
|
||||
} else {
|
||||
|
@ -674,6 +673,25 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
|
|||
return result;
|
||||
}
|
||||
|
||||
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
|
||||
// Specular requires either/or, default factors of zero disables specular, so do not export
|
||||
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
// The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0
|
||||
const bool colorFactorIsZero = specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2];
|
||||
if (specular.specularFactor == 0.0f && colorFactorIsZero) {
|
||||
return false;
|
||||
} else if (specular.specularFactor == 0.0f) {
|
||||
specular.specularFactor = 1.0f;
|
||||
} else if (colorFactorIsZero) {
|
||||
specular.specularColorFactor[0] = specular.specularColorFactor[1] = specular.specularColorFactor[2] = 1.0f;
|
||||
}
|
||||
GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR);
|
||||
GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
|
||||
// Return true if got any valid Sheen properties or textures
|
||||
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
|
||||
|
@ -818,9 +836,9 @@ void glTF2Exporter::ExportMaterials() {
|
|||
m->alphaMode = alphaMode.C_Str();
|
||||
}
|
||||
|
||||
{
|
||||
// This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default.
|
||||
if (mProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) {
|
||||
// KHR_materials_pbrSpecularGlossiness extension
|
||||
// NOTE: This extension is being considered for deprecation (Dec 2020)
|
||||
PbrSpecularGlossiness pbrSG;
|
||||
if (GetMatSpecGloss(mat, pbrSG)) {
|
||||
mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
|
||||
|
@ -837,7 +855,12 @@ void glTF2Exporter::ExportMaterials() {
|
|||
} else {
|
||||
// These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness
|
||||
if (!m->pbrSpecularGlossiness.isPresent) {
|
||||
// Sheen
|
||||
MaterialSpecular specular;
|
||||
if (GetMatSpecular(mat, specular)) {
|
||||
mAsset->extensionsUsed.KHR_materials_specular = true;
|
||||
m->materialSpecular = Nullable<MaterialSpecular>(specular);
|
||||
}
|
||||
|
||||
MaterialSheen sheen;
|
||||
if (GetMatSheen(mat, sheen)) {
|
||||
mAsset->extensionsUsed.KHR_materials_sheen = true;
|
||||
|
|
|
@ -76,6 +76,7 @@ struct OcclusionTextureInfo;
|
|||
struct Node;
|
||||
struct Texture;
|
||||
struct PbrSpecularGlossiness;
|
||||
struct MaterialSpecular;
|
||||
struct MaterialSheen;
|
||||
struct MaterialClearcoat;
|
||||
struct MaterialTransmission;
|
||||
|
@ -117,6 +118,7 @@ protected:
|
|||
aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec4 &prop, const char *propName, int type, int idx) const;
|
||||
aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec3 &prop, const char *propName, int type, int idx) const;
|
||||
bool GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG);
|
||||
bool GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular);
|
||||
bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen);
|
||||
bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat);
|
||||
bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission);
|
||||
|
|
|
@ -278,8 +278,19 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
|
|||
aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
|
||||
aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
|
||||
|
||||
// KHR_materials_specular
|
||||
if (mat.materialSpecular.isPresent) {
|
||||
MaterialSpecular &specular = mat.materialSpecular.value;
|
||||
// Default values of zero disables Specular
|
||||
if (std::memcmp(specular.specularColorFactor, defaultSpecularColorFactor, sizeof(glTFCommon::vec3)) != 0 || specular.specularFactor != 0.0f) {
|
||||
SetMaterialColorProperty(r, specular.specularColorFactor, aimat, AI_MATKEY_COLOR_SPECULAR);
|
||||
aimat->AddProperty(&specular.specularFactor, 1, AI_MATKEY_SPECULAR_FACTOR);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularTexture, aimat, aiTextureType_SPECULAR);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularColorTexture, aimat, aiTextureType_SPECULAR);
|
||||
}
|
||||
}
|
||||
// pbrSpecularGlossiness
|
||||
if (mat.pbrSpecularGlossiness.isPresent) {
|
||||
else if (mat.pbrSpecularGlossiness.isPresent) {
|
||||
PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
|
||||
|
||||
SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
@ -453,6 +464,11 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
unsigned int k = 0;
|
||||
meshOffsets.clear();
|
||||
|
||||
|
||||
std::vector<unsigned int> usedVertexIndices;
|
||||
std::vector<unsigned int> reverseMappingIndices;
|
||||
std::vector<unsigned int> indexBuffer;
|
||||
|
||||
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||
Mesh &mesh = r.meshes[m];
|
||||
|
||||
|
@ -462,6 +478,50 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
|
||||
Mesh::Primitive &prim = mesh.primitives[p];
|
||||
|
||||
Mesh::Primitive::Attributes &attr = prim.attributes;
|
||||
|
||||
// Find out the maximum number of vertices:
|
||||
size_t numAllVertices = 0;
|
||||
if (!attr.position.empty() && attr.position[0]) {
|
||||
numAllVertices = attr.position[0]->count;
|
||||
}
|
||||
|
||||
// Extract used vertices:
|
||||
bool useIndexBuffer = prim.indices;
|
||||
std::vector<unsigned int>* vertexRemappingTable = nullptr;
|
||||
if (useIndexBuffer) {
|
||||
size_t count = prim.indices->count;
|
||||
indexBuffer.resize(count);
|
||||
usedVertexIndices.clear();
|
||||
reverseMappingIndices.clear();
|
||||
usedVertexIndices.reserve(count / 3); // this is a very rough heuristic to reduce re-allocations
|
||||
vertexRemappingTable = &usedVertexIndices;
|
||||
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||
if (!data.IsValid()) {
|
||||
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
|
||||
}
|
||||
|
||||
// Build the vertex remapping table and the modified index buffer (used later instead of the original one)
|
||||
// In case no index buffer is used, the original vertex arrays are being used so no remapping is required in the first place.
|
||||
const unsigned int unusedIndex = ~0u;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
unsigned int index = data.GetUInt(i);
|
||||
if (index >= numAllVertices) {
|
||||
// Out-of-range indices will be filtered out when adding the faces and then lead to a warning. At this stage, we just keep them.
|
||||
indexBuffer[i] = index;
|
||||
continue;
|
||||
}
|
||||
if (index >= reverseMappingIndices.size()) {
|
||||
reverseMappingIndices.resize(index + 1, unusedIndex);
|
||||
}
|
||||
if (reverseMappingIndices[index] == unusedIndex) {
|
||||
reverseMappingIndices[index] = static_cast<unsigned int>(usedVertexIndices.size());
|
||||
usedVertexIndices.push_back(index);
|
||||
}
|
||||
indexBuffer[i] = reverseMappingIndices[index];
|
||||
}
|
||||
}
|
||||
|
||||
aiMesh *aim = new aiMesh();
|
||||
meshes.push_back(std::unique_ptr<aiMesh>(aim));
|
||||
|
||||
|
@ -491,28 +551,25 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
break;
|
||||
}
|
||||
|
||||
Mesh::Primitive::Attributes &attr = prim.attributes;
|
||||
|
||||
if (!attr.position.empty() && attr.position[0]) {
|
||||
aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->count);
|
||||
attr.position[0]->ExtractData(aim->mVertices);
|
||||
aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->ExtractData(aim->mVertices, vertexRemappingTable));
|
||||
}
|
||||
|
||||
if (!attr.normal.empty() && attr.normal[0]) {
|
||||
if (attr.normal[0]->count != aim->mNumVertices) {
|
||||
if (attr.normal[0]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Normal count in mesh \"", mesh.name, "\" does not match the vertex count, normals ignored.");
|
||||
} else {
|
||||
attr.normal[0]->ExtractData(aim->mNormals);
|
||||
attr.normal[0]->ExtractData(aim->mNormals, vertexRemappingTable);
|
||||
|
||||
// only extract tangents if normals are present
|
||||
if (!attr.tangent.empty() && attr.tangent[0]) {
|
||||
if (attr.tangent[0]->count != aim->mNumVertices) {
|
||||
if (attr.tangent[0]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Tangent count in mesh \"", mesh.name, "\" does not match the vertex count, tangents ignored.");
|
||||
} else {
|
||||
// generate bitangents from normals and tangents according to spec
|
||||
Tangent *tangents = nullptr;
|
||||
|
||||
attr.tangent[0]->ExtractData(tangents);
|
||||
attr.tangent[0]->ExtractData(tangents, vertexRemappingTable);
|
||||
|
||||
aim->mTangents = new aiVector3D[aim->mNumVertices];
|
||||
aim->mBitangents = new aiVector3D[aim->mNumVertices];
|
||||
|
@ -529,7 +586,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
|
||||
for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
|
||||
if (attr.color[c]->count != aim->mNumVertices) {
|
||||
if (attr.color[c]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Color stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
|
@ -537,7 +594,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
|
||||
auto componentType = attr.color[c]->componentType;
|
||||
if (componentType == glTF2::ComponentType_FLOAT) {
|
||||
attr.color[c]->ExtractData(aim->mColors[c]);
|
||||
attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable);
|
||||
} else {
|
||||
if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) {
|
||||
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c]);
|
||||
|
@ -552,13 +609,13 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (attr.texcoord[tc]->count != aim->mNumVertices) {
|
||||
if (attr.texcoord[tc]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Texcoord stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
}
|
||||
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc], vertexRemappingTable);
|
||||
aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
|
||||
|
||||
aiVector3D *values = aim->mTextureCoords[tc];
|
||||
|
@ -583,11 +640,11 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
Mesh::Primitive::Target &target = targets[i];
|
||||
|
||||
if (needPositions) {
|
||||
if (target.position[0]->count != aim->mNumVertices) {
|
||||
if (target.position[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Positions of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
aiVector3D *positionDiff = nullptr;
|
||||
target.position[0]->ExtractData(positionDiff);
|
||||
target.position[0]->ExtractData(positionDiff, vertexRemappingTable);
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||
aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId];
|
||||
}
|
||||
|
@ -595,11 +652,11 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
}
|
||||
if (needNormals) {
|
||||
if (target.normal[0]->count != aim->mNumVertices) {
|
||||
if (target.normal[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Normals of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
aiVector3D *normalDiff = nullptr;
|
||||
target.normal[0]->ExtractData(normalDiff);
|
||||
target.normal[0]->ExtractData(normalDiff, vertexRemappingTable);
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||
aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId];
|
||||
}
|
||||
|
@ -610,14 +667,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
if (!aiAnimMesh.HasNormals()) {
|
||||
// prevent nullptr access to aiAnimMesh.mNormals below when no normals are available
|
||||
ASSIMP_LOG_WARN("Bitangents of target ", i, " in mesh \"", mesh.name, "\" can't be computed, because mesh has no normals.");
|
||||
} else if (target.tangent[0]->count != aim->mNumVertices) {
|
||||
} else if (target.tangent[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Tangents of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
Tangent *tangent = nullptr;
|
||||
attr.tangent[0]->ExtractData(tangent);
|
||||
attr.tangent[0]->ExtractData(tangent, vertexRemappingTable);
|
||||
|
||||
aiVector3D *tangentDiff = nullptr;
|
||||
target.tangent[0]->ExtractData(tangentDiff);
|
||||
target.tangent[0]->ExtractData(tangentDiff, vertexRemappingTable);
|
||||
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) {
|
||||
tangent[vertexId].xyz += tangentDiff[vertexId];
|
||||
|
@ -641,20 +698,15 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
aiFace *facePtr = nullptr;
|
||||
size_t nFaces = 0;
|
||||
|
||||
if (prim.indices) {
|
||||
size_t count = prim.indices->count;
|
||||
|
||||
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||
if (!data.IsValid()) {
|
||||
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
|
||||
}
|
||||
if (useIndexBuffer) {
|
||||
size_t count = indexBuffer.size();
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i));
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, indexBuffer[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -667,7 +719,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -676,12 +728,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[1]);
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[i - 1], indexBuffer[i]);
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast<int>(count) - 1), faces[0].mIndices[0]);
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[static_cast<int>(count) - 1], faces[0].mIndices[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -694,7 +746,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -705,10 +757,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
// The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
// For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i + 1], indexBuffer[i], indexBuffer[i + 2]);
|
||||
} else {
|
||||
// For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -716,9 +768,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[1], indexBuffer[2]);
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1172,11 +1224,6 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
|||
|
||||
if (node.camera) {
|
||||
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
||||
if (node.translation.isPresent) {
|
||||
aiVector3D trans;
|
||||
CopyValue(node.translation.value, trans);
|
||||
pScene->mCameras[node.camera.GetIndex()]->mPosition = trans;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.light) {
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -47,14 +45,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CIOStreamWrapper::~CIOStreamWrapper() {
|
||||
/* Various places depend on this destructor to close the file */
|
||||
if (mFile) {
|
||||
// Various places depend on this destructor to close the file
|
||||
if (mFile != nullptr) {
|
||||
|
||||
mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile);
|
||||
}
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t CIOStreamWrapper::Read(void *pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount) {
|
||||
|
@ -62,7 +62,7 @@ size_t CIOStreamWrapper::Read(void *pvBuffer,
|
|||
return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t CIOStreamWrapper::Write(const void *pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount) {
|
||||
|
@ -70,23 +70,23 @@ size_t CIOStreamWrapper::Write(const void *pvBuffer,
|
|||
return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn CIOStreamWrapper::Seek(size_t pOffset,
|
||||
aiOrigin pOrigin) {
|
||||
return mFile->SeekProc(mFile, pOffset, pOrigin);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t CIOStreamWrapper::Tell() const {
|
||||
return mFile->TellProc(mFile);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t CIOStreamWrapper::FileSize() const {
|
||||
return mFile->FileSizeProc(mFile);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CIOStreamWrapper::Flush() {
|
||||
return mFile->FlushProc(mFile);
|
||||
}
|
||||
|
|
|
@ -47,48 +47,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/cfileio.h>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
class CIOSystemWrapper;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Custom IOStream implementation for the C-API
|
||||
class CIOStreamWrapper : public IOStream {
|
||||
/// @brief Custom IOStream implementation for the C-API-
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class CIOStreamWrapper final : public IOStream {
|
||||
public:
|
||||
explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) :
|
||||
mFile(pFile),
|
||||
mIO(io) {}
|
||||
~CIOStreamWrapper(void);
|
||||
|
||||
size_t Read(void *pvBuffer, size_t pSize, size_t pCount);
|
||||
size_t Write(const void *pvBuffer, size_t pSize, size_t pCount);
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin);
|
||||
size_t Tell(void) const;
|
||||
size_t FileSize() const;
|
||||
void Flush();
|
||||
explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io);
|
||||
~CIOStreamWrapper() override;
|
||||
size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override;
|
||||
size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override;
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
|
||||
size_t Tell(void) const override;
|
||||
size_t FileSize() const override;
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
aiFile *mFile;
|
||||
CIOSystemWrapper *mIO;
|
||||
};
|
||||
|
||||
class CIOSystemWrapper : public IOSystem {
|
||||
inline CIOStreamWrapper::CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) :
|
||||
mFile(pFile),
|
||||
mIO(io) {
|
||||
ai_assert(io != nullptr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/// @brief Custom IO-System wrapper implementation for the C-API.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class CIOSystemWrapper final : public IOSystem {
|
||||
friend class CIOStreamWrapper;
|
||||
|
||||
public:
|
||||
explicit CIOSystemWrapper(aiFileIO *pFile) :
|
||||
mFileSystem(pFile) {}
|
||||
|
||||
bool Exists(const char *pFile) const;
|
||||
char getOsSeparator() const;
|
||||
IOStream *Open(const char *pFile, const char *pMode = "rb");
|
||||
void Close(IOStream *pFile);
|
||||
explicit CIOSystemWrapper(aiFileIO *pFile);
|
||||
~CIOSystemWrapper() override = default;
|
||||
bool Exists(const char *pFile) const override;
|
||||
char getOsSeparator() const override;
|
||||
IOStream *Open(const char *pFile, const char *pMode = "rb") override;
|
||||
void Close(IOStream *pFile) override;
|
||||
|
||||
private:
|
||||
aiFileIO *mFileSystem;
|
||||
};
|
||||
|
||||
inline CIOSystemWrapper::CIOSystemWrapper(aiFileIO *pFile) : mFileSystem(pFile) {
|
||||
ai_assert(pFile != nullptr);
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
#endif // AI_CIOSYSTEM_H_INCLUDED
|
||||
|
|
|
@ -194,6 +194,8 @@ SET( Common_SRCS
|
|||
Common/ScenePreprocessor.cpp
|
||||
Common/ScenePreprocessor.h
|
||||
Common/SkeletonMeshBuilder.cpp
|
||||
Common/StackAllocator.h
|
||||
Common/StackAllocator.inl
|
||||
Common/StandardShapes.cpp
|
||||
Common/TargetAnimation.cpp
|
||||
Common/TargetAnimation.h
|
||||
|
@ -218,6 +220,12 @@ SET( CApi_SRCS
|
|||
)
|
||||
SOURCE_GROUP(CApi FILES ${CApi_SRCS})
|
||||
|
||||
SET(Geometry_SRCS
|
||||
Geometry/GeometryUtils.h
|
||||
Geometry/GeometryUtils.cpp
|
||||
)
|
||||
SOURCE_GROUP(Geometry FILES ${Geometry_SRCS})
|
||||
|
||||
SET( STEPParser_SRCS
|
||||
AssetLib/STEPParser/STEPFileReader.h
|
||||
AssetLib/STEPParser/STEPFileReader.cpp
|
||||
|
@ -1129,6 +1137,7 @@ SET( assimp_src
|
|||
${Core_SRCS}
|
||||
${CApi_SRCS}
|
||||
${Common_SRCS}
|
||||
${Geometry_SRCS}
|
||||
${Logging_SRCS}
|
||||
${Exporter_SRCS}
|
||||
${PostProcessing_SRCS}
|
||||
|
@ -1188,7 +1197,61 @@ TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
|
|||
IF (ASSIMP_WARNINGS_AS_ERRORS)
|
||||
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
|
||||
IF (MSVC)
|
||||
TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX)
|
||||
|
||||
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
|
||||
TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror
|
||||
-Wno-unused-function
|
||||
-Wno-microsoft-enum-value
|
||||
-Wno-switch-enum
|
||||
-Wno-covered-switch-default
|
||||
-Wno-reserved-identifier
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-c++98-compat
|
||||
-Wno-documentation
|
||||
-Wno-documentation-unknown-command
|
||||
-Wno-deprecated-dynamic-exception-spec
|
||||
-Wno-undef
|
||||
-Wno-suggest-destructor-override
|
||||
-Wno-suggest-override
|
||||
-Wno-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-variable-declarations
|
||||
-Wno-extra-semi
|
||||
-Wno-nonportable-system-include-path
|
||||
-Wno-undefined-reinterpret-cast
|
||||
-Wno-shift-sign-overflow
|
||||
-Wno-deprecated
|
||||
-Wno-format-nonliteral
|
||||
-Wno-comma
|
||||
-Wno-implicit-fallthrough
|
||||
-Wno-unused-template
|
||||
-Wno-undefined-func-template
|
||||
-Wno-declaration-after-statement
|
||||
)
|
||||
ELSE()
|
||||
TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror)
|
||||
ENDIF()
|
||||
|
@ -1327,7 +1390,7 @@ ENDIF()
|
|||
|
||||
# Add RT-extension library for glTF importer with Open3DGC-compression.
|
||||
IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
|
||||
TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY})
|
||||
TARGET_LINK_LIBRARIES(assimp rt)
|
||||
ENDIF ()
|
||||
|
||||
|
||||
|
|
|
@ -214,7 +214,12 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
|
|||
// Some importers may be unimplemented or otherwise unsuitable for general use
|
||||
// in their current state. Devs can set ASSIMP_ENABLE_DEV_IMPORTERS in their
|
||||
// local environment to enable them, otherwise they're left out of the registry.
|
||||
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
|
||||
// not supported under uwp
|
||||
const char *envStr = std::getenv("ASSIMP_ENABLE_DEV_IMPORTERS");
|
||||
#else
|
||||
const char *envStr = { "0" };
|
||||
#endif
|
||||
bool devImportersEnabled = envStr && strcmp(envStr, "0");
|
||||
|
||||
// Ensure no unused var warnings if all uses are #ifndef'd away below:
|
||||
|
@ -377,9 +382,6 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
|
|||
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
|
||||
out.push_back(new IQMImporter());
|
||||
#endif
|
||||
//#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
|
||||
// out.push_back(new StepFile::StepFileImporter());
|
||||
//#endif
|
||||
}
|
||||
|
||||
/** will delete all registered importers. */
|
||||
|
|
|
@ -74,26 +74,8 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
|
|||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) {
|
||||
// Point in triangle test using baryzentric coordinates
|
||||
const aiVector2D v0 = p1 - p0;
|
||||
const aiVector2D v1 = p2 - p0;
|
||||
const aiVector2D v2 = pp - p0;
|
||||
|
||||
double dot00 = v0 * v0;
|
||||
double dot11 = v1 * v1;
|
||||
const double dot01 = v0 * v1;
|
||||
const double dot02 = v0 * v2;
|
||||
const double dot12 = v1 * v2;
|
||||
const double denom = dot00 * dot11 - dot01 * dot01;
|
||||
if (denom == 0.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const double invDenom = 1.0 / denom;
|
||||
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||
|
||||
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
|
||||
// pp should be left side of the three triangle side, by ccw arrow
|
||||
return OnLeftSideOfLine2D(p0, p1, pp) && OnLeftSideOfLine2D(p1, p2, pp) && OnLeftSideOfLine2D(p2, p0, pp);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) {
|
|||
case AI_AIVECTOR3D:
|
||||
out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData));
|
||||
break;
|
||||
case AI_AIMETADATA:
|
||||
out.mData = new aiMetadata(*static_cast<aiMetadata *>(in.mData));
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
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.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file StackAllocator.h
|
||||
* @brief A very bare-bone allocator class that is suitable when
|
||||
* allocating many small objects, e.g. during parsing.
|
||||
* Individual objects are not freed, instead only the whole memory
|
||||
* can be deallocated.
|
||||
*/
|
||||
#ifndef AI_STACK_ALLOCATOR_H_INC
|
||||
#define AI_STACK_ALLOCATOR_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/** @brief A very bare-bone allocator class that is suitable when
|
||||
* allocating many small objects, e.g. during parsing.
|
||||
* Individual objects are not freed, instead only the whole memory
|
||||
* can be deallocated.
|
||||
*/
|
||||
class StackAllocator {
|
||||
public:
|
||||
/// @brief Constructs the allocator
|
||||
inline StackAllocator();
|
||||
/// @brief Destructs the allocator and frees all memory
|
||||
inline ~StackAllocator();
|
||||
|
||||
// non copyable
|
||||
StackAllocator(const StackAllocator &) = delete;
|
||||
StackAllocator &operator=(const StackAllocator &) = delete;
|
||||
|
||||
/// @brief Returns a pointer to byteSize bytes of heap memory that persists
|
||||
/// for the lifetime of the allocator (or until FreeAll is called).
|
||||
inline void *Allocate(size_t byteSize);
|
||||
|
||||
/// @brief Releases all the memory owned by this allocator.
|
||||
// Memory provided through function Allocate is not valid anymore after this function has been called.
|
||||
inline void FreeAll();
|
||||
|
||||
private:
|
||||
constexpr const static size_t g_maxBytesPerBlock = 64 * 1024 * 1024; // The maximum size (in bytes) of a block
|
||||
constexpr const static size_t g_startBytesPerBlock = 16 * 1024; // Size of the first block. Next blocks will double in size until maximum size of g_maxBytesPerBlock
|
||||
size_t m_blockAllocationSize = g_startBytesPerBlock; // Block size of the current block
|
||||
size_t m_subIndex = g_maxBytesPerBlock; // The current byte offset in the current block
|
||||
std::vector<uint8_t *> m_storageBlocks; // A list of blocks
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#include "StackAllocator.inl"
|
||||
|
||||
#endif // include guard
|
|
@ -1,17 +1,14 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
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:
|
||||
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
|
||||
|
@ -38,55 +35,48 @@ 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.
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
|
||||
#define ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
|
||||
#include "StackAllocator.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
using namespace Assimp;
|
||||
|
||||
namespace AssimpSamples {
|
||||
namespace SharedCode {
|
||||
|
||||
// Used to convert between multibyte and unicode strings.
|
||||
class UTFConverter {
|
||||
using UTFConverterImpl = std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>;
|
||||
public:
|
||||
UTFConverter(const char* s) :
|
||||
s_(s),
|
||||
ws_(impl_.from_bytes(s)) {
|
||||
}
|
||||
UTFConverter(const wchar_t* s) :
|
||||
s_(impl_.to_bytes(s)),
|
||||
ws_(s) {
|
||||
}
|
||||
UTFConverter(const std::string& s) :
|
||||
s_(s),
|
||||
ws_(impl_.from_bytes(s)) {
|
||||
}
|
||||
UTFConverter(const std::wstring& s) :
|
||||
s_(impl_.to_bytes(s)),
|
||||
ws_(s) {
|
||||
}
|
||||
inline const char* c_str() const {
|
||||
return s_.c_str();
|
||||
}
|
||||
inline const std::string& str() const {
|
||||
return s_;
|
||||
}
|
||||
inline const wchar_t* c_wstr() const {
|
||||
return ws_.c_str();
|
||||
}
|
||||
private:
|
||||
static UTFConverterImpl impl_;
|
||||
std::string s_;
|
||||
std::wstring ws_;
|
||||
};
|
||||
|
||||
}
|
||||
inline StackAllocator::StackAllocator() {
|
||||
}
|
||||
|
||||
#endif // ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H
|
||||
inline StackAllocator::~StackAllocator() {
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
inline void *StackAllocator::Allocate(size_t byteSize) {
|
||||
if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block
|
||||
{
|
||||
// double block size every time, up to maximum of g_maxBytesPerBlock.
|
||||
// Block size must be at least as large as byteSize, but we want to use this for small allocations anyway.
|
||||
m_blockAllocationSize = std::max(std::min(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize);
|
||||
uint8_t *data = new uint8_t[m_blockAllocationSize];
|
||||
m_storageBlocks.emplace_back(data);
|
||||
m_subIndex = byteSize;
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t *data = m_storageBlocks.back();
|
||||
data += m_subIndex;
|
||||
m_subIndex += byteSize;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
inline void StackAllocator::FreeAll() {
|
||||
for (size_t i = 0; i < m_storageBlocks.size(); i++) {
|
||||
delete [] m_storageBlocks[i];
|
||||
}
|
||||
std::vector<uint8_t *> empty;
|
||||
m_storageBlocks.swap(empty);
|
||||
// start over:
|
||||
m_blockAllocationSize = g_startBytesPerBlock;
|
||||
m_subIndex = g_maxBytesPerBlock;
|
||||
}
|
|
@ -50,7 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
void mydummy() {}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -78,7 +81,7 @@ public:
|
|||
};
|
||||
|
||||
typedef std::vector<unsigned int> UIntVector;
|
||||
typedef std::map<uint64_t, Edge> EdgeMap;
|
||||
typedef std::unordered_map<uint64_t, Edge> EdgeMap;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hashing function to derive an index into an #EdgeMap from two given
|
||||
|
|
|
@ -68,7 +68,7 @@ class ZipFile : public IOStream {
|
|||
|
||||
public:
|
||||
std::string m_Filename;
|
||||
virtual ~ZipFile();
|
||||
virtual ~ZipFile() override;
|
||||
|
||||
// IOStream interface
|
||||
size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override;
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
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 ) {
|
||||
const ai_real s = (a + b + c) / 2;
|
||||
const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
|
||||
return area;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ai_real GeometryUtils::distance3D( const aiVector3D &vA, const 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 );
|
||||
const ai_real a = lx*lx + ly*ly + lz*lz;
|
||||
const ai_real d = pow( a, (ai_real)0.5 );
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
|
||||
ai_real area = 0;
|
||||
|
||||
const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
|
||||
const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
|
||||
const aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
|
||||
|
||||
const ai_real a = distance3D( vA, vB );
|
||||
const ai_real b = distance3D( vB, vC );
|
||||
const ai_real c = distance3D( vC, vA );
|
||||
area = heron( a, b, c );
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a ray intersects a plane and find the intersection point
|
||||
bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
||||
const aiVector3D& planeNormal, aiVector3D& pos) {
|
||||
const ai_real b = planeNormal * (planePos - ray.pos);
|
||||
ai_real h = ray.dir * planeNormal;
|
||||
if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0)
|
||||
return false;
|
||||
|
||||
pos = ray.pos + (ray.dir * h);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut,
|
||||
size_t numVectors) {
|
||||
for (size_t i=0; i<numVectors; ++i) {
|
||||
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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 ASSIMP_API 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, const 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 );
|
||||
|
||||
/// @brief Will calculate the intersection between a ray and a plane
|
||||
/// @param ray The ray to test for
|
||||
/// @param planePos A point on the plane
|
||||
/// @param planeNormal The plane normal to describe its orientation
|
||||
/// @param pos The position of the intersection.
|
||||
/// @return true is an intersection was detected, false if not.
|
||||
static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos);
|
||||
|
||||
/// @brief Will normalize an array of vectors.
|
||||
/// @param vectorArrayIn The incoming arra of vectors.
|
||||
/// @param vectorArrayOut The normalized vectors.
|
||||
/// @param numVectors The array size.
|
||||
static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors);
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
|
@ -43,15 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate::ArmaturePopulate() = default;
|
||||
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones) {
|
||||
for (aiBone *bone : bones) {
|
||||
if (bone->mName == bone_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// The class destructor.
|
||||
ArmaturePopulate::~ArmaturePopulate() = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_PopulateArmatureData) != 0;
|
||||
|
@ -70,7 +73,7 @@ void ArmaturePopulate::Execute(aiScene *out) {
|
|||
BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
|
||||
BuildNodeList(out->mRootNode, nodes);
|
||||
|
||||
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
|
||||
BuildBoneStack(out->mRootNode, out, bones, bone_stack, nodes);
|
||||
|
||||
ASSIMP_LOG_DEBUG("Bone stack size: ", bone_stack.size());
|
||||
|
||||
|
@ -78,9 +81,8 @@ void ArmaturePopulate::Execute(aiScene *out) {
|
|||
aiBone *bone = kvp.first;
|
||||
aiNode *bone_node = kvp.second;
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str());
|
||||
|
||||
// lcl transform grab - done in generate_nodes :)
|
||||
|
||||
// bone->mOffsetMatrix = bone_node->mTransformation;
|
||||
aiNode *armature = GetArmatureRoot(bone_node, bones);
|
||||
|
||||
ai_assert(armature);
|
||||
|
@ -159,8 +161,7 @@ void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
|
|||
// A bone stack allows us to have multiple armatures, with the same bone names
|
||||
// A bone stack allows us also to retrieve bones true transform even with
|
||||
// duplicate names :)
|
||||
void ArmaturePopulate::BuildBoneStack(aiNode *,
|
||||
const aiNode *root_node,
|
||||
void ArmaturePopulate::BuildBoneStack(const aiNode *root_node,
|
||||
const aiScene*,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
|
@ -196,8 +197,7 @@ void ArmaturePopulate::BuildBoneStack(aiNode *,
|
|||
// This is required to be detected for a bone initially, it will recurse up
|
||||
// until it cannot find another bone and return the node No known failure
|
||||
// points. (yet)
|
||||
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list) {
|
||||
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, std::vector<aiBone *> &bone_list) {
|
||||
while (nullptr != bone_node) {
|
||||
if (!IsBoneNode(bone_node->mName, bone_list)) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
|
||||
|
@ -212,18 +212,6 @@ aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Simple IsBoneNode check if this could be a bone
|
||||
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones) {
|
||||
for (aiBone *bone : bones) {
|
||||
if (bone->mName == bone_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop this node by name from the stack if found
|
||||
// Used in multiple armature situations with duplicate node / bone names
|
||||
// Known flaw: cannot have nodes with bone names, will be fixed in later release
|
||||
|
|
|
@ -69,10 +69,10 @@ namespace Assimp {
|
|||
class ASSIMP_API ArmaturePopulate : public BaseProcess {
|
||||
public:
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate();
|
||||
ArmaturePopulate() = default;
|
||||
|
||||
/// The class destructor.
|
||||
virtual ~ArmaturePopulate();
|
||||
virtual ~ArmaturePopulate() = default;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual bool IsActive( unsigned int pFlags ) const;
|
||||
|
@ -86,9 +86,6 @@ public:
|
|||
static aiNode *GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
|
@ -99,7 +96,7 @@ public:
|
|||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
|
||||
static void BuildBoneStack(const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
|
@ -108,5 +105,4 @@ public:
|
|||
|
||||
} // Namespace Assimp
|
||||
|
||||
|
||||
#endif // SCALE_PROCESS_H_
|
||||
|
|
|
@ -60,10 +60,6 @@ CalcTangentsProcess::CalcTangentsProcess() :
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
CalcTangentsProcess::~CalcTangentsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
|
||||
|
|
|
@ -59,14 +59,11 @@ namespace Assimp
|
|||
* because the joining of vertices also considers tangents and bitangents for
|
||||
* uniqueness.
|
||||
*/
|
||||
class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
|
||||
{
|
||||
class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess {
|
||||
public:
|
||||
|
||||
CalcTangentsProcess();
|
||||
~CalcTangentsProcess();
|
||||
~CalcTangentsProcess() override = default;
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
|
@ -74,24 +71,21 @@ public:
|
|||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
// setter for configMaxAngle
|
||||
inline void SetMaxSmoothAngle(float f)
|
||||
{
|
||||
void SetMaxSmoothAngle(float f) {
|
||||
configMaxAngle =f;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Calculates tangents and bitangents for a specific mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
|
@ -103,10 +97,9 @@ protected:
|
|||
/** Executes the post processing step on the given imported data.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
float configMaxAngle;
|
||||
unsigned int configSourceUV;
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -42,8 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file GenUVCoords step */
|
||||
|
||||
|
||||
#include "ComputeUVMappingProcess.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
|
@ -51,47 +50,25 @@ using namespace Assimp;
|
|||
|
||||
namespace {
|
||||
|
||||
const static aiVector3D base_axis_y(0.0,1.0,0.0);
|
||||
const static aiVector3D base_axis_x(1.0,0.0,0.0);
|
||||
const static aiVector3D base_axis_z(0.0,0.0,1.0);
|
||||
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;
|
||||
const static aiVector3D base_axis_y(0.0, 1.0, 0.0);
|
||||
const static aiVector3D base_axis_x(1.0, 0.0, 0.0);
|
||||
const static aiVector3D base_axis_z(0.0, 0.0, 1.0);
|
||||
const static ai_real angle_epsilon = ai_real(0.95);
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_GenUVCoords) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a ray intersects a plane and find the intersection point
|
||||
inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
||||
const aiVector3D& planeNormal, aiVector3D& pos)
|
||||
{
|
||||
const ai_real b = planeNormal * (planePos - ray.pos);
|
||||
ai_real h = ray.dir * planeNormal;
|
||||
if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0)
|
||||
return false;
|
||||
|
||||
pos = ray.pos + (ray.dir * h);
|
||||
return true;
|
||||
bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_GenUVCoords) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find the first empty UV channel in a mesh
|
||||
inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
||||
{
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
||||
if (!mesh->mTextureCoords[m])return m;
|
||||
inline unsigned int FindEmptyUVChannel(aiMesh *mesh) {
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++m)
|
||||
if (!mesh->mTextureCoords[m]) {
|
||||
return m;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found");
|
||||
return UINT_MAX;
|
||||
|
@ -99,22 +76,22 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Try to remove UV seams
|
||||
void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
||||
{
|
||||
void RemoveUVSeams(aiMesh *mesh, aiVector3D *out) {
|
||||
// TODO: just a very rough algorithm. I think it could be done
|
||||
// much easier, but I don't know how and am currently too tired to
|
||||
// to think about a better solution.
|
||||
|
||||
const static ai_real LOWER_LIMIT = ai_real( 0.1 );
|
||||
const static ai_real UPPER_LIMIT = ai_real( 0.9 );
|
||||
const static ai_real LOWER_LIMIT = ai_real(0.1);
|
||||
const static ai_real UPPER_LIMIT = ai_real(0.9);
|
||||
|
||||
const static ai_real LOWER_EPSILON = ai_real( 10e-3 );
|
||||
const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 );
|
||||
const static ai_real LOWER_EPSILON = ai_real(10e-3);
|
||||
const static ai_real UPPER_EPSILON = ai_real(1.0 - 10e-3);
|
||||
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces; ++fidx) {
|
||||
const aiFace &face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) {
|
||||
continue; // triangles and polygons only, please
|
||||
}
|
||||
|
||||
unsigned int smallV = face.mNumIndices, large = smallV;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
|
@ -123,20 +100,18 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
// but the assumption that a face with at least one very small
|
||||
// on the one side and one very large U coord on the other side
|
||||
// lies on a UV seam should work for most cases.
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT) {
|
||||
smallV = n;
|
||||
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
zero = true;
|
||||
else round_to_zero = true;
|
||||
else
|
||||
round_to_zero = true;
|
||||
}
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
||||
{
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT) {
|
||||
large = n;
|
||||
|
||||
// If we have a U value very close to 1 we can't
|
||||
|
@ -145,10 +120,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
one = true;
|
||||
}
|
||||
}
|
||||
if (smallV != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (smallV != face.mNumIndices && large != face.mNumIndices) {
|
||||
for (unsigned int n = 0; n < face.mNumIndices; ++n) {
|
||||
// If the u value is over the upper limit and no other u
|
||||
// value of that face is 0, round it to 0
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
||||
|
@ -164,9 +137,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
// Due to numerical inaccuracies one U coord becomes 0, the
|
||||
// other 1. But we do still have a third UV coord to determine
|
||||
// to which side we must round to.
|
||||
else if (one && zero)
|
||||
{
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
else if (one && zero) {
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
out[face.mIndices[n]].x = 0.0;
|
||||
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
out[face.mIndices[n]].x = 1.0;
|
||||
|
@ -177,8 +149,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
|
||||
|
@ -186,7 +157,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
|
|||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
|
||||
// For each point get a normalized projection vector in the sphere,
|
||||
// get its longitude and latitude and map them to their respective
|
||||
|
@ -200,58 +171,54 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
|
|||
// Thus we can derive:
|
||||
// lat = arcsin (z)
|
||||
// lon = arctan (y/x)
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
} else if (axis * base_axis_y >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
} else if (axis * base_axis_z >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D diff = ((mTrafo * mesh->mVertices[pnt]) - center).Normalize();
|
||||
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
|
||||
(std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
RemoveUVSeams(mesh, out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.x - min.x;
|
||||
|
||||
|
@ -259,116 +226,110 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
|
|||
// directly to the texture V axis. The other axis is derived from
|
||||
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
||||
// 'c' is the center point of the mesh.
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
aiVector3D &uv = out[pnt];
|
||||
|
||||
uv.y = (pos.x - min.x) / diff;
|
||||
uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
uv.x = (std::atan2(pos.z - center.z, pos.y - center.y) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
} else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.y - min.y;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
aiVector3D &uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
} else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const ai_real diff = max.z - min.z;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
aiVector3D &uv = out[pnt];
|
||||
|
||||
uv.y = (pos.z - min.z) / diff;
|
||||
uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
uv.x = (std::atan2(pos.y - center.y, pos.x - center.x) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
|
||||
const ai_real diff = max.y - min.y;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
|
||||
const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
||||
aiVector3D &uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI;
|
||||
uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
RemoveUVSeams(mesh, out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
ai_real diffu,diffv;
|
||||
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
|
||||
ai_real diffu, diffv;
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.z - min.z;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.z - min.z) / diffu, (pos.y - min.y) / diffv, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
} else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
} else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0);
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D &pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu, (pos.y - min.y) / diffv, 0.0);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else
|
||||
{
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
|
||||
const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0);
|
||||
out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,14 +337,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
|
||||
{
|
||||
void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh *, aiVector3D *) {
|
||||
ASSIMP_LOG_ERROR("Mapping type currently not implemented");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void ComputeUVMappingProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
|
||||
char buffer[1024];
|
||||
|
||||
|
@ -394,23 +353,18 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
|
||||
/* Iterate through all materials and search for non-UV mapped textures
|
||||
*/
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||
mappingStack.clear();
|
||||
aiMaterial* mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
||||
{
|
||||
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
aiMaterial *mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
|
||||
aiMaterialProperty *prop = mat->mProperties[a];
|
||||
if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
|
||||
aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping) {
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
|
||||
aiTextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
|
||||
MappingTypeToString(mapping));
|
||||
aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
|
||||
MappingTypeToString(mapping));
|
||||
|
||||
ASSIMP_LOG_INFO(buffer);
|
||||
}
|
||||
|
@ -418,70 +372,62 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
if (aiTextureMapping_OTHER == mapping)
|
||||
continue;
|
||||
|
||||
MappingInfo info (mapping);
|
||||
MappingInfo info(mapping);
|
||||
|
||||
// Get further properties - currently only the major axis
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
||||
{
|
||||
aiMaterialProperty* prop2 = mat->mProperties[a2];
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
|
||||
aiMaterialProperty *prop2 = mat->mProperties[a2];
|
||||
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
|
||||
continue;
|
||||
|
||||
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) {
|
||||
info.axis = *((aiVector3D*)prop2->mData);
|
||||
if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) {
|
||||
info.axis = *((aiVector3D *)prop2->mData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int idx( 99999999 );
|
||||
unsigned int idx(99999999);
|
||||
|
||||
// Check whether we have this mapping mode already
|
||||
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
||||
if (mappingStack.end() != it)
|
||||
{
|
||||
std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
|
||||
if (mappingStack.end() != it) {
|
||||
idx = (*it).uv;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
|
||||
aiMesh *mesh = pScene->mMeshes[m];
|
||||
unsigned int outIdx = 0;
|
||||
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
|
||||
!mesh->mNumVertices)
|
||||
{
|
||||
if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
|
||||
!mesh->mNumVertices) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate output storage
|
||||
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
switch (mapping)
|
||||
{
|
||||
switch (mapping) {
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,info.axis,p);
|
||||
ComputeSphereMapping(mesh, info.axis, p);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,info.axis,p);
|
||||
ComputeCylinderMapping(mesh, info.axis, p);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,info.axis,p);
|
||||
ComputePlaneMapping(mesh, info.axis, p);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh,p);
|
||||
ComputeBoxMapping(mesh, p);
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
if (m && idx != outIdx)
|
||||
{
|
||||
if (m && idx != outIdx) {
|
||||
ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
}
|
||||
idx = outIdx;
|
||||
}
|
||||
|
@ -491,7 +437,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
|
||||
// Update the material property list
|
||||
mapping = aiTextureMapping_UV;
|
||||
((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
||||
((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,13 +59,10 @@ namespace Assimp {
|
|||
/** ComputeUVMappingProcess - converts special mappings, such as spherical,
|
||||
* cylindrical or boxed to proper UV coordinates for rendering.
|
||||
*/
|
||||
class ComputeUVMappingProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
ComputeUVMappingProcess();
|
||||
~ComputeUVMappingProcess();
|
||||
|
||||
class ComputeUVMappingProcess : public BaseProcess {
|
||||
public:
|
||||
ComputeUVMappingProcess() = default;
|
||||
~ComputeUVMappingProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
|
@ -73,14 +70,14 @@ public:
|
|||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -125,8 +122,7 @@ protected:
|
|||
private:
|
||||
|
||||
// temporary structure to describe a mapping
|
||||
struct MappingInfo
|
||||
{
|
||||
struct MappingInfo {
|
||||
explicit MappingInfo(aiTextureMapping _type)
|
||||
: type (_type)
|
||||
, axis (0.f,1.f,0.f)
|
||||
|
@ -137,8 +133,7 @@ private:
|
|||
aiVector3D axis;
|
||||
unsigned int uv;
|
||||
|
||||
bool operator== (const MappingInfo& other)
|
||||
{
|
||||
bool operator== (const MappingInfo& other) {
|
||||
return type == other.type && axis == other.axis;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -79,14 +77,6 @@ void flipUVs(aiMeshType *pMesh) {
|
|||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
MakeLeftHandedProcess::MakeLeftHandedProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
MakeLeftHandedProcess::~MakeLeftHandedProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
|
||||
|
@ -121,6 +111,12 @@ void MakeLeftHandedProcess::Execute(aiScene *pScene) {
|
|||
ProcessAnimation(nodeAnim);
|
||||
}
|
||||
}
|
||||
|
||||
// process the cameras accordingly
|
||||
for( unsigned int a = 0; a < pScene->mNumCameras; ++a)
|
||||
{
|
||||
ProcessCamera(pScene->mCameras[a]);
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
|
||||
}
|
||||
|
||||
|
@ -227,18 +223,18 @@ void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) {
|
|||
|
||||
// rotation keys
|
||||
for (unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) {
|
||||
/* That's the safe version, but the float errors add up. So we try the short version instead
|
||||
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
|
||||
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
|
||||
rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
|
||||
aiQuaternion rotquat( rotmat);
|
||||
pAnim->mRotationKeys[a].mValue = rotquat;
|
||||
*/
|
||||
pAnim->mRotationKeys[a].mValue.x *= -1.0f;
|
||||
pAnim->mRotationKeys[a].mValue.y *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single camera to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessCamera( aiCamera* pCam)
|
||||
{
|
||||
pCam->mLookAt = ai_real(2.0f) * pCam->mPosition - pCam->mLookAt;
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
// # FlipUVsProcess
|
||||
|
@ -305,14 +301,6 @@ void FlipUVsProcess::ProcessMesh(aiMesh *pMesh) {
|
|||
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
||||
// # FlipWindingOrderProcess
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FlipWindingOrderProcess::FlipWindingOrderProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FlipWindingOrderProcess::~FlipWindingOrderProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -59,6 +58,7 @@ struct aiMesh;
|
|||
struct aiNodeAnim;
|
||||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
struct aiCamera;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
|
@ -72,22 +72,18 @@ namespace Assimp {
|
|||
*
|
||||
* @note RH-LH and LH-RH is the same, so this class can be used for both
|
||||
*/
|
||||
class MakeLeftHandedProcess : public BaseProcess
|
||||
{
|
||||
|
||||
|
||||
class MakeLeftHandedProcess : public BaseProcess {
|
||||
public:
|
||||
MakeLeftHandedProcess();
|
||||
~MakeLeftHandedProcess();
|
||||
MakeLeftHandedProcess() = default;
|
||||
~MakeLeftHandedProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Recursively converts a node and all of its children
|
||||
*/
|
||||
|
@ -114,30 +110,36 @@ protected:
|
|||
* @param pAnim The bone animation to transform
|
||||
*/
|
||||
void ProcessAnimation( aiNodeAnim* pAnim);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single camera to left handed coordinates.
|
||||
* The camera viewing direction is inverted by reflecting mLookAt
|
||||
* across mPosition.
|
||||
* @param pCam The camera to convert
|
||||
*/
|
||||
void ProcessCamera( aiCamera* pCam);
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Postprocessing step to flip the face order of the imported data
|
||||
*/
|
||||
class FlipWindingOrderProcess : public BaseProcess
|
||||
{
|
||||
class FlipWindingOrderProcess : public BaseProcess {
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipWindingOrderProcess();
|
||||
FlipWindingOrderProcess() = default;
|
||||
|
||||
/** Destructor, private as well */
|
||||
~FlipWindingOrderProcess();
|
||||
~FlipWindingOrderProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
public:
|
||||
/** Some other types of post-processing require winding order flips */
|
||||
static void ProcessMesh( aiMesh* pMesh);
|
||||
};
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -43,42 +42,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
/// @file DeboneProcess.cpp
|
||||
/** Implementation of the DeboneProcess post processing step */
|
||||
|
||||
|
||||
|
||||
// internal headers of the post-processing framework
|
||||
#include "ProcessHelper.h"
|
||||
#include "DeboneProcess.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
DeboneProcess::DeboneProcess()
|
||||
{
|
||||
mNumBones = 0;
|
||||
mNumBonesCanDoWithout = 0;
|
||||
|
||||
mThreshold = AI_DEBONE_THRESHOLD;
|
||||
mAllOrNone = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
DeboneProcess::~DeboneProcess() = default;
|
||||
DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool DeboneProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool DeboneProcess::IsActive( unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_Debone) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void DeboneProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
void DeboneProcess::SetupProperties(const Importer* pImp) {
|
||||
// get the current value of the property
|
||||
mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
|
||||
mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
|
||||
|
@ -86,8 +69,7 @@ void DeboneProcess::SetupProperties(const Importer* pImp)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void DeboneProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void DeboneProcess::Execute( aiScene* pScene) {
|
||||
ASSIMP_LOG_DEBUG("DeboneProcess begin");
|
||||
|
||||
if(!pScene->mNumMeshes) {
|
||||
|
@ -104,7 +86,7 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
|
||||
for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if(splitList[a]) {
|
||||
numSplits++;
|
||||
++numSplits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,10 +99,8 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
// build a new array of meshes for the scene
|
||||
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];
|
||||
|
||||
std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
|
||||
|
||||
if(splitList[a]) {
|
||||
|
@ -138,8 +118,8 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
aiNode *theNode = find ? pScene->mRootNode->FindNode(*find) : nullptr;
|
||||
std::pair<unsigned int,aiNode*> push_pair(static_cast<unsigned int>(meshes.size()),theNode);
|
||||
|
||||
mSubMeshIndices[a].push_back(push_pair);
|
||||
meshes.push_back(newMeshes[b].first);
|
||||
mSubMeshIndices[a].emplace_back(push_pair);
|
||||
meshes.emplace_back(newMeshes[b].first);
|
||||
|
||||
out+=newMeshes[b].first->mNumBones;
|
||||
}
|
||||
|
@ -150,8 +130,7 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].emplace_back(static_cast<unsigned int>(meshes.size()), (aiNode *)nullptr);
|
||||
meshes.push_back(srcMesh);
|
||||
|
@ -173,8 +152,7 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Counts bones total/removable in a given mesh.
|
||||
bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
||||
{
|
||||
bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) {
|
||||
if(!pMesh->HasBones()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -193,25 +171,23 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
|||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||
|
||||
if(w==0.0f) {
|
||||
if (w == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||
if(w>=mThreshold) {
|
||||
|
||||
if(vertexBones[vid]!=cUnowned) {
|
||||
if(vertexBones[vid]==i) //double entry
|
||||
{
|
||||
if (w >= mThreshold) {
|
||||
if (vertexBones[vid] != cUnowned) {
|
||||
//double entry
|
||||
if(vertexBones[vid]==i) {
|
||||
ASSIMP_LOG_WARN("Encountered double entry in bone weights");
|
||||
}
|
||||
else //TODO: track attraction in order to break tie
|
||||
{
|
||||
} else {
|
||||
//TODO: track attraction in order to break tie
|
||||
vertexBones[vid] = cCoowned;
|
||||
}
|
||||
}
|
||||
else vertexBones[vid] = i;
|
||||
} else {
|
||||
vertexBones[vid] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isBoneNecessary[i]) {
|
||||
|
@ -227,13 +203,16 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
|||
if(isInterstitialRequired) {
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
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]];
|
||||
|
||||
if(v!=w) {
|
||||
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||
if (v != w) {
|
||||
if(v<pMesh->mNumBones) {
|
||||
isBoneNecessary[v] = true;
|
||||
}
|
||||
if (w<pMesh->mNumBones) {
|
||||
isBoneNecessary[w] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,8 +231,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Splits the given mesh by bone count.
|
||||
void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
|
||||
{
|
||||
void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const {
|
||||
// same deal here as ConsiderMesh basically
|
||||
|
||||
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||
|
@ -371,8 +349,7 @@ void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMe
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void DeboneProcess::UpdateNode(aiNode* pNode) const
|
||||
{
|
||||
void DeboneProcess::UpdateNode(aiNode* pNode) const {
|
||||
// rebuild the node's mesh index list
|
||||
|
||||
std::vector<unsigned int> newMeshList;
|
||||
|
@ -382,9 +359,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
|
|||
unsigned int m = static_cast<unsigned int>(pNode->mNumMeshes), n = static_cast<unsigned int>(mSubMeshIndices.size());
|
||||
|
||||
// first pass, look for meshes which have not moved
|
||||
|
||||
for(unsigned int a=0;a<m;a++) {
|
||||
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
|
||||
unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());
|
||||
|
@ -398,8 +373,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
|
|||
|
||||
// second pass, collect deboned meshes
|
||||
|
||||
for(unsigned int a=0;a<n;a++)
|
||||
{
|
||||
for(unsigned int a=0;a<n;a++) {
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
|
||||
unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());
|
||||
|
||||
|
@ -430,8 +404,7 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Apply the node transformation to a mesh
|
||||
void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
|
||||
{
|
||||
void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const {
|
||||
// Check whether we need to transform the coordinates at all
|
||||
if (!mat.IsIdentity()) {
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Assimp {
|
|||
class DeboneProcess : public BaseProcess {
|
||||
public:
|
||||
DeboneProcess();
|
||||
~DeboneProcess();
|
||||
~DeboneProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
|
@ -79,14 +79,14 @@ public:
|
|||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
protected:
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -94,7 +94,7 @@ protected:
|
|||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Counts bones total/removable in a given mesh.
|
||||
|
|
|
@ -42,35 +42,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
/** @file Implementation of the post processing step to drop face
|
||||
* normals for all imported faces.
|
||||
*/
|
||||
|
||||
* normals for all imported faces.
|
||||
*/
|
||||
|
||||
#include "DropFaceNormalsProcess.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
DropFaceNormalsProcess::DropFaceNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
DropFaceNormalsProcess::~DropFaceNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_DropNormals) != 0;
|
||||
bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_DropNormals) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void DropFaceNormalsProcess::Execute( aiScene* pScene) {
|
||||
void DropFaceNormalsProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin");
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
|
||||
|
@ -78,21 +69,21 @@ void DropFaceNormalsProcess::Execute( aiScene* pScene) {
|
|||
}
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]);
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
bHas |= this->DropMeshFaceNormals(pScene->mMeshes[a]);
|
||||
}
|
||||
if (bHas) {
|
||||
if (bHas) {
|
||||
ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. "
|
||||
"Face normals have been removed");
|
||||
"Face normals have been removed");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. "
|
||||
"No normals were present");
|
||||
"No normals were present");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* mesh) {
|
||||
bool DropFaceNormalsProcess::DropMeshFaceNormals(aiMesh *mesh) {
|
||||
ai_assert(nullptr != mesh);
|
||||
|
||||
if (nullptr == mesh->mNormals) {
|
||||
|
|
|
@ -55,8 +55,8 @@ namespace Assimp {
|
|||
*/
|
||||
class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess {
|
||||
public:
|
||||
DropFaceNormalsProcess();
|
||||
~DropFaceNormalsProcess();
|
||||
DropFaceNormalsProcess() = default;
|
||||
~DropFaceNormalsProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
|
@ -64,15 +64,14 @@ public:
|
|||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
private:
|
||||
bool DropMeshFaceNormals(aiMesh* pcMesh);
|
||||
|
|
|
@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
EmbedTexturesProcess::EmbedTexturesProcess() = default;
|
||||
|
||||
EmbedTexturesProcess::~EmbedTexturesProcess() = default;
|
||||
|
||||
bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_EmbedTextures) != 0;
|
||||
}
|
||||
|
|
|
@ -62,19 +62,19 @@ namespace Assimp {
|
|||
class ASSIMP_API EmbedTexturesProcess : public BaseProcess {
|
||||
public:
|
||||
/// The default class constructor.
|
||||
EmbedTexturesProcess();
|
||||
EmbedTexturesProcess() = default;
|
||||
|
||||
/// The class destructor.
|
||||
virtual ~EmbedTexturesProcess();
|
||||
~EmbedTexturesProcess() override = default;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual bool IsActive(unsigned int pFlags) const;
|
||||
bool IsActive(unsigned int pFlags) const override;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void Execute(aiScene* pScene);
|
||||
virtual void Execute(aiScene* pScene) override;
|
||||
|
||||
private:
|
||||
// Resolve the path and add the file content to the scene as a texture.
|
||||
|
|
|
@ -41,10 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file FindDegenerates.cpp
|
||||
* @brief Implementation of the FindDegenerates post-process step.
|
||||
*/
|
||||
*/
|
||||
|
||||
#include "ProcessHelper.h"
|
||||
#include "FindDegenerates.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
|
@ -53,39 +54,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
// Correct node indices to meshes and remove references to deleted mesh
|
||||
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap);
|
||||
static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FindDegeneratesProcess::FindDegeneratesProcess() :
|
||||
mConfigRemoveDegenerates( false ),
|
||||
mConfigCheckAreaOfTriangle( false ){
|
||||
mConfigRemoveDegenerates(false),
|
||||
mConfigCheckAreaOfTriangle(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FindDegeneratesProcess::~FindDegeneratesProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
|
||||
bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_FindDegenerates);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup import configuration
|
||||
void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
|
||||
void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
|
||||
// Get the current value of AI_CONFIG_PP_FD_REMOVE
|
||||
mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
|
||||
mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
|
||||
mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
|
||||
mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
||||
void FindDegeneratesProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
|
||||
if ( nullptr == pScene) {
|
||||
if (nullptr == pScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -115,7 +112,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
|||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
|
||||
}
|
||||
|
||||
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) {
|
||||
static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap) {
|
||||
unsigned int targetIndex = 0;
|
||||
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
|
||||
const unsigned int sourceMeshIndex = pNode->mMeshes[i];
|
||||
|
@ -126,56 +123,25 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
|
|||
}
|
||||
}
|
||||
pNode->mNumMeshes = targetIndex;
|
||||
//recurse to all children
|
||||
// recurse to all children
|
||||
for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
|
||||
updateSceneGraph(pNode->mChildren[i], meshMap);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
||||
bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
|
||||
mesh->mPrimitiveTypes = 0;
|
||||
|
||||
std::vector<bool> remove_me;
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me.resize( mesh->mNumFaces, false );
|
||||
remove_me.resize(mesh->mNumFaces, false);
|
||||
}
|
||||
|
||||
unsigned int deg = 0, limit;
|
||||
for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
|
||||
aiFace& face = mesh->mFaces[a];
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||
aiFace &face = mesh->mFaces[a];
|
||||
bool first = true;
|
||||
|
||||
// check whether the face contains degenerated entries
|
||||
|
@ -185,43 +151,43 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
// double points may not come directly after another.
|
||||
limit = face.mNumIndices;
|
||||
if (face.mNumIndices > 4) {
|
||||
limit = std::min( limit, i+2 );
|
||||
limit = std::min(limit, i + 2);
|
||||
}
|
||||
|
||||
for (unsigned int t = i+1; t < limit; ++t) {
|
||||
if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
|
||||
for (unsigned int t = i + 1; t < limit; ++t) {
|
||||
if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
|
||||
// we have found a matching vertex position
|
||||
// remove the corresponding index from the array
|
||||
--face.mNumIndices;
|
||||
--limit;
|
||||
for (unsigned int m = t; m < face.mNumIndices; ++m) {
|
||||
face.mIndices[ m ] = face.mIndices[ m+1 ];
|
||||
face.mIndices[m] = face.mIndices[m + 1];
|
||||
}
|
||||
--t;
|
||||
|
||||
// NOTE: we set the removed vertex index to an unique value
|
||||
// to make sure the developer gets notified when his
|
||||
// application attempts to access this data.
|
||||
face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
|
||||
face.mIndices[face.mNumIndices] = 0xdeadbeef;
|
||||
|
||||
if(first) {
|
||||
if (first) {
|
||||
++deg;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if ( mConfigRemoveDegenerates ) {
|
||||
remove_me[ a ] = true;
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me[a] = true;
|
||||
goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mConfigCheckAreaOfTriangle ) {
|
||||
if ( face.mNumIndices == 3 ) {
|
||||
ai_real area = calculateAreaOfTriangle( face, mesh );
|
||||
if (mConfigCheckAreaOfTriangle) {
|
||||
if (face.mNumIndices == 3) {
|
||||
ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
|
||||
if (area < ai_epsilon) {
|
||||
if ( mConfigRemoveDegenerates ) {
|
||||
remove_me[ a ] = true;
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me[a] = true;
|
||||
++deg;
|
||||
goto evil_jump_outside;
|
||||
}
|
||||
|
@ -233,8 +199,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
}
|
||||
|
||||
// We need to update the primitive flags array of the mesh.
|
||||
switch (face.mNumIndices)
|
||||
{
|
||||
switch (face.mNumIndices) {
|
||||
case 1u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
|
@ -248,30 +213,28 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
break;
|
||||
};
|
||||
evil_jump_outside:
|
||||
evil_jump_outside:
|
||||
continue;
|
||||
}
|
||||
|
||||
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
|
||||
if (mConfigRemoveDegenerates && deg) {
|
||||
unsigned int n = 0;
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
|
||||
{
|
||||
aiFace& face_src = mesh->mFaces[a];
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||
aiFace &face_src = mesh->mFaces[a];
|
||||
if (!remove_me[a]) {
|
||||
aiFace& face_dest = mesh->mFaces[n++];
|
||||
aiFace &face_dest = mesh->mFaces[n++];
|
||||
|
||||
// Do a manual copy, keep the index array
|
||||
face_dest.mNumIndices = face_src.mNumIndices;
|
||||
face_dest.mIndices = face_src.mIndices;
|
||||
face_dest.mIndices = face_src.mIndices;
|
||||
|
||||
if (&face_src != &face_dest) {
|
||||
// clear source
|
||||
face_src.mNumIndices = 0;
|
||||
face_src.mIndices = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Otherwise delete it if we don't need this face
|
||||
delete[] face_src.mIndices;
|
||||
face_src.mIndices = nullptr;
|
||||
|
@ -281,15 +244,15 @@ evil_jump_outside:
|
|||
// Just leave the rest of the array unreferenced, we don't care for now
|
||||
mesh->mNumFaces = n;
|
||||
if (!mesh->mNumFaces) {
|
||||
//The whole mesh consists of degenerated faces
|
||||
//signal upward, that this mesh should be deleted.
|
||||
// The whole mesh consists of degenerated faces
|
||||
// signal upward, that this mesh should be deleted.
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (deg && !DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_WARN( "Found ", deg, " degenerated primitives");
|
||||
ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -59,19 +59,19 @@ namespace Assimp {
|
|||
class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
|
||||
public:
|
||||
FindDegeneratesProcess();
|
||||
~FindDegeneratesProcess();
|
||||
~FindDegeneratesProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Check whether step is active
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Execute step on a given scene
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Setup import settings
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Execute step on a given mesh
|
||||
|
@ -105,23 +105,19 @@ private:
|
|||
bool mConfigCheckAreaOfTriangle;
|
||||
};
|
||||
|
||||
inline
|
||||
void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
|
||||
inline void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
|
||||
mConfigRemoveDegenerates = enabled;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FindDegeneratesProcess::IsInstantRemoval() const {
|
||||
inline bool FindDegeneratesProcess::IsInstantRemoval() const {
|
||||
return mConfigRemoveDegenerates;
|
||||
}
|
||||
|
||||
inline
|
||||
void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
|
||||
inline void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
|
||||
mConfigCheckAreaOfTriangle = enabled;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FindDegeneratesProcess::isAreaCheckEnabled() const {
|
||||
inline bool FindDegeneratesProcess::isAreaCheckEnabled() const {
|
||||
return mConfigCheckAreaOfTriangle;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,6 @@ FindInstancesProcess::FindInstancesProcess()
|
|||
: configSpeedFlag (false)
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FindInstancesProcess::~FindInstancesProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FindInstancesProcess::IsActive( unsigned int pFlags) const
|
||||
|
|
|
@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
class FindInstancesProcessTest;
|
||||
namespace Assimp {
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Get a pseudo(!)-hash representing a mesh.
|
||||
|
@ -60,8 +61,7 @@ namespace Assimp {
|
|||
* @param in Input mesh
|
||||
* @return Hash.
|
||||
*/
|
||||
inline
|
||||
uint64_t GetMeshHash(aiMesh* in) {
|
||||
inline uint64_t GetMeshHash(aiMesh* in) {
|
||||
ai_assert(nullptr != in);
|
||||
|
||||
// ... get an unique value representing the vertex format of the mesh
|
||||
|
@ -83,8 +83,7 @@ uint64_t GetMeshHash(aiMesh* in) {
|
|||
* @param e Epsilon
|
||||
* @return true if the arrays are identical
|
||||
*/
|
||||
inline
|
||||
bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
|
||||
inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
|
||||
unsigned int size, float e) {
|
||||
for (const aiVector3D* end = first+size; first != end; ++first,++second) {
|
||||
if ( (*first - *second).SquareLength() >= e)
|
||||
|
@ -107,31 +106,27 @@ inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second,
|
|||
// ---------------------------------------------------------------------------
|
||||
/** @brief A post-processing steps to search for instanced meshes
|
||||
*/
|
||||
class FindInstancesProcess : public BaseProcess
|
||||
{
|
||||
class FindInstancesProcess : public BaseProcess {
|
||||
public:
|
||||
|
||||
FindInstancesProcess();
|
||||
~FindInstancesProcess();
|
||||
~FindInstancesProcess() override = default;
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
// Check whether step is active in given flags combination
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Execute step on a given scene
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Setup properties prior to executing the process
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
private:
|
||||
|
||||
bool configSpeedFlag;
|
||||
|
||||
}; // ! end class FindInstancesProcess
|
||||
|
||||
} // ! end namespace Assimp
|
||||
|
||||
#endif // !! AI_FINDINSTANCES_H_INC
|
||||
|
|
|
@ -60,10 +60,6 @@ FindInvalidDataProcess::FindInvalidDataProcess() :
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FindInvalidDataProcess::~FindInvalidDataProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
|
||||
|
|
|
@ -64,35 +64,37 @@ namespace Assimp {
|
|||
* which have zero normal vectors. */
|
||||
class ASSIMP_API FindInvalidDataProcess : public BaseProcess {
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/// The default class constructor / destructor.
|
||||
FindInvalidDataProcess();
|
||||
~FindInvalidDataProcess();
|
||||
~FindInvalidDataProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
bool IsActive(unsigned int pFlags) const;
|
||||
/// Returns active state.
|
||||
bool IsActive(unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Setup import settings
|
||||
void SetupProperties(const Importer *pImp);
|
||||
/// Setup import settings
|
||||
void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Run the step
|
||||
void Execute(aiScene *pScene);
|
||||
/// Run the step
|
||||
void Execute(aiScene *pScene) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given mesh
|
||||
* @param pMesh The mesh to process.
|
||||
* @return 0 - nothing, 1 - removed sth, 2 - please delete me */
|
||||
/// Executes the post-processing step on the given mesh
|
||||
/// @param pMesh The mesh to process.
|
||||
/// @return 0 - nothing, 1 - removed sth, 2 - please delete me */
|
||||
int ProcessMesh(aiMesh *pMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given animation
|
||||
* @param anim The animation to process. */
|
||||
/// Executes the post-processing step on the given animation
|
||||
/// @param anim The animation to process. */
|
||||
void ProcessAnimation(aiAnimation *anim);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given anim channel
|
||||
* @param anim The animation channel to process.*/
|
||||
/// Executes the post-processing step on the given anim channel
|
||||
/// @param anim The animation channel to process.*/
|
||||
void ProcessAnimationChannel(aiNodeAnim *anim);
|
||||
|
||||
private:
|
||||
|
|
|
@ -56,26 +56,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FixInfacingNormalsProcess::FixInfacingNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FixInfacingNormalsProcess::~FixInfacingNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_FixInfacingNormals) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FixInfacingNormalsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void FixInfacingNormalsProcess::Execute( aiScene* pScene) {
|
||||
ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin");
|
||||
|
||||
bool bHas( false );
|
||||
|
|
|
@ -49,8 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiMesh;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The FixInfacingNormalsProcess tries to determine whether the normal
|
||||
|
@ -59,8 +58,10 @@ namespace Assimp
|
|||
*/
|
||||
class FixInfacingNormalsProcess : public BaseProcess {
|
||||
public:
|
||||
FixInfacingNormalsProcess();
|
||||
~FixInfacingNormalsProcess();
|
||||
// -------------------------------------------------------------------
|
||||
/// The default class constructor / destructor.
|
||||
FixInfacingNormalsProcess() = default;
|
||||
~FixInfacingNormalsProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
|
@ -68,14 +69,14 @@ public:
|
|||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive( unsigned int pFlags) const override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute( aiScene* pScene) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -48,10 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
GenBoundingBoxesProcess::GenBoundingBoxesProcess() = default;
|
||||
|
||||
GenBoundingBoxesProcess::~GenBoundingBoxesProcess() = default;
|
||||
|
||||
bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != ( pFlags & aiProcess_GenBoundingBoxes );
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ conditions are met:
|
|||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
s
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
|
@ -54,18 +54,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
/** Post-processing process to find axis-aligned bounding volumes for amm meshes
|
||||
* used in a scene
|
||||
/**
|
||||
* @brief Post-processing process to find axis-aligned bounding volumes for amm meshes
|
||||
* used in a scene.
|
||||
*/
|
||||
class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess {
|
||||
public:
|
||||
/// The class constructor.
|
||||
GenBoundingBoxesProcess();
|
||||
/// The class destructor.
|
||||
~GenBoundingBoxesProcess();
|
||||
/// Will return true, if aiProcess_GenBoundingBoxes is defined.
|
||||
// -------------------------------------------------------------------
|
||||
/// The default class constructor / destructor.
|
||||
GenBoundingBoxesProcess() = default;
|
||||
~GenBoundingBoxesProcess() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// @brief Will return true, if aiProcess_GenBoundingBoxes is defined.
|
||||
bool IsActive(unsigned int pFlags) const override;
|
||||
/// The execution callback.
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// @brief The execution callback.
|
||||
void Execute(aiScene* pScene) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -54,14 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
GenFaceNormalsProcess::GenFaceNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
GenFaceNormalsProcess::~GenFaceNormalsProcess() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue