Compare commits

..
Author SHA1 Message Date
Kim Kulling 30b20e07e7 Fix possible overflow 2025-09-23 21:28:54 +02:00
Kim Kulling fa18d3dde6 Fix possible overflow 2025-09-23 21:24:58 +02:00
Paul BauriegelandKim Kulling 709fe3c3d0 Add BOM skip and fix mtl parsing (#6253)
* Add BOM skip and fix mtl parsing
* Remove old code
* Fix #5635
* Add all attributes to ObjFileData
---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-22 11:20:24 +02:00
Matt PennyandKim Kulling 489c8d565b Restore merging of near-identical vertices for JoinIdenticalVertices (#6278)
* Restore merging of near-identical vertices for JoinIdenticalVertices

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-21 10:57:17 +02:00
Luca Della Vedova 0581ed5f11 Added tangent handedness to glTF export (#6322)
* Added tangent handedness to glTF export
2025-09-18 14:10:41 +02:00
fifth_lightandKim Kulling 5c568616ec Fix hasTangentsAndBitangents method in AiMesh.java (#6345)
original code m_tangents != null && m_tangents != null; triggers error prone

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-18 10:09:43 +02:00
AbdulRehman 45cb880835 Fixed Build.md (#6354)
* Fixed itch.io spelling from itchi.io
2025-09-18 09:34:55 +02:00
dd98d4aea3 PyAssimp: Re-add 'aiProcess_Triangulate' (#6335)
apparently, b9bfac0418 accidentally
removed a couple of lines with a botched copy'n'paste.

Co-authored-by: IOhannes m zmölnig <zmoelnig@umlautT.umlaeute.mur.at>
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-17 10:23:37 +02:00
AbdulRehman 01ac320de8 Better README! Fixed discord link as well (#6351)
* Better README!
2025-09-17 08:16:38 +02:00
AbdulRehman a815a78433 Updated doc/Preamble.txt & SECURITY.md (#6338)
* Update LICENSE

* Update Preamble.txt

* Update SECURITY.md

* Remove GitHub's default comment
2025-09-10 13:59:00 +02:00
69f8eb21fd fix large glb reading by providing a proper helper for reading size_t type (#6307)
Co-authored-by: Vitaly Ovchinnikov <v@ovch.ru>
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-09 14:27:17 +02:00
Kim Kulling 72b9939b9f Add null check for aiNode in AddNode method (#6348)
- Added null check for node in AddNode function.
- closes https://github.com/assimp/assimp/issues/6347
2025-09-09 14:10:07 +02:00
Steven FrenchandKim Kulling 4c8a3bd39c [CMake] -l (#6329)
- Fix zlib linkage.

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-09-04 09:32:37 +02:00
Kim Kulling 8ef3838beb FBX: Fix offset calculation by adding cursor check (#6337)
- closes https://github.com/assimp/assimp/issues/6336
2025-08-28 11:48:38 +02:00
AbdulRehman 441884387f Update LICENSE (#6327) 2025-08-27 20:16:18 +02:00
Pranav PandKim Kulling f7bbf6dc15 Fix endiannes issues regarding floats on s390x (#6276) (#6277)
* Fix endiannes issues regarding floats on s390x (#6276)

* Fix CI Warnings

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-26 15:34:33 +02:00
Kyungjoon KoandKim Kulling aadd49311a Fix OOB read in OpenDDLParser::parsePrimitiveDataType (#6315)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-25 15:03:00 +02:00
dependabot[bot]andKim Kulling 3f107bebf2 Bump actions/download-artifact from 4 to 5 (#6319)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-22 20:26:58 +02:00
Sergei TrofimovichandKim Kulling a38ec50fd3 test/unit/utProfiler.cpp: fix gcc-16 build failure (#6267)
* test/unit/utProfiler.cpp: fix `gcc-16` build failure

Upcoming `gcc-16` improved detection of unused variables as:

    test/unit/utProfiler.cpp: In member function 'virtual void utProfiler_addRegion_success_Test::TestBody()':
    test/unit/utProfiler.cpp:71:22: error: variable 'j' set but not used [-Werror=unused-but-set-variable=]
       71 |         volatile int j=0;
          |                      ^

The change is intentional accoring to Andrew Pinsi and is not a faalse positive.

* Update utProfiler.cpp: Remove dead code

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-21 10:15:01 +02:00
Dongge LiuandKim Kulling 4c42db1805 Fixed a heap-use-after-free in SortByPTypeProcess. (#6326)
The process incorrectly deleted original meshes from the scene when cleaning up after an error if those meshes had been added to its output list (outMeshes). The fix ensures proper ownership transfer by nullifying the original mesh pointer in the scene (pScene->mMeshes[i] = nullptr;) when the mesh is moved to outMeshes. This prevents the scene destructor from attempting to delete the mesh again later, while allowing the error cleanup path in SortByPTypeProcess to correctly delete all meshes it owns (both newly created and transferred originals).

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-21 09:31:15 +02:00
dependabot[bot] 26e2372882 Bump actions/checkout from 4 to 5 (#6328)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 12:50:30 +02:00
Dongge LiuandKim Kulling 36b004e286 Fixed a heap-buffer-overflow in the Half-Life 1 MDL loader. (#6321)
The loader attempted to read the MDL header without verifying if the input buffer was large enough.
Added a check in MDLImporter::InternReadFile_HL1 to ensure the buffer size is sufficient before proceeding with loading.

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-18 09:29:45 +03:00
Kyungjoon KoandKim Kulling 3a0ee8792f Fix OOB read (2) in OpenDDLParser::parsePrimitiveDataType (#6316)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-14 13:51:07 +03:00
Kyungjoon KoandKim Kulling e3f9cf5564 Fix OOB read in OpenDDLParser::parseReference (#6317)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-08-10 14:48:27 +03:00
Kyungjoon Ko 6d7ea78792 Fix SEGV write in Assimp::SortByPTypeProcess::Execute (#6318)
* Fix OOB Write in Assimp::SortByPTypeProcess::Execute
2025-08-10 11:45:30 +03:00
Dongge Liu 13316790aa Fixed a container-overflow error (#6298)
* Fixed a container-overflow error in `ODDLParser::OpenDDLParser::parseIntegerLiteral` by swapping the order of conditions in a while loop to ensure the end-of-buffer check happens before dereferencing the pointer. This prevents reading past the end of the buffer when lookForNextToken returns the end pointer.

https://oss-fuzz.com/testcase-detail/4980126616780800
https://issues.oss-fuzz.com/issues/42527625

* Update OpenDDLParser.cpp
2025-08-02 21:25:40 +02:00
Kim KullingandKim Kulling 9255412906 Add CMakePreset file (#6295)
Co-authored-by: Kim Kulling <kim.kulling@draeger.com>
2025-07-30 13:53:21 +02:00
sSsA01andKim Kulling 8355e0c4bc Fix to fail in the function fast_atoreal_move when the flag ASSIMP_DOUBLE_PRESICION is enabled (#6250)
* Refix export fbx PolygonVertexIndex

* Fix the function ColladaParser::ReadEffectColor when the flag ASSIMP_DOUBLE_PRESICION is enabled

* Fix the static function ReadLight in ColladaParser when the flag ASSIMP_DOUBLE_PRESICION is enabled

* Refactor of the call of the function fast_atoreal_move to the member of aiColor3D

* Fix the call of the function fast_atoreal_move when the flag ASSIMP_DOUBLE_PRESICION is enabled and and refactor

* Fix the call of the function fast_atoreal_move when the flag ASSIMP_DOUBLE_PRESICION is enabled

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-07-29 14:19:50 +02:00
DIGITAL IMAGE DESIGNandKim Kulling 6fa9d09a97 AC: Support Double-Sided Faces (#6252)
* AC: Support Double-Sided Faces

The AC format marks double-sided SURF elements with the 0x20 flag, which Assimp ignored. This commit adds support for double-sided faces.

On encountering a double-sided face via the flag mentioned above, the front face is generated as usual but is then duplicated. The winding order of the duplicate is flipped to form a back face. Vertices are duplicated too so that back faces work correctly with normal vector generation and face smoothing.

* Add test file

* Simplify test case

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
2025-07-29 13:09:30 +02:00
Kim KullingandKim Kulling 9f4e7c6d8d Refactoring: use using types (#6266)
* Refactoring: use using types

---------

Co-authored-by: Kim Kulling <kim.kulling@draeger.com>
2025-07-28 17:00:45 +02:00
Kim Kulling 59bc03d931 X3D: Fix invalid vector::back usage (#6283)
* X3D: Fix invalid vector::back usage
2025-07-25 15:01:16 +02:00
Panthuncia edcb350129 Update Build.md (#6273)
Update build instructions to include information about USD importer special-case to ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT, and about ASSIMP_BUILD_USD_IMPORTER.
2025-07-22 21:08:33 +02:00
90 changed files with 700 additions and 2519 deletions
+2 -2
View File
@@ -48,7 +48,7 @@ jobs:
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true
@@ -188,7 +188,7 @@ jobs:
- id: upload-url
run: |
echo "url=$(cat create-release/release_upload_url.txt)" >> $GITHUB_OUTPUT
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
- uses: actions/upload-release-asset@v1
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
os: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v5
- uses: lukka/get-cmake@latest
+3 -3
View File
@@ -14,7 +14,7 @@ jobs:
name: adress-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
@@ -38,7 +38,7 @@ jobs:
name: undefined-behavior-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
@@ -62,7 +62,7 @@ jobs:
name: printf-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: run scan_printf script
run: ./scripts/scan_printf.sh
+4 -3
View File
@@ -67,7 +67,7 @@ The cmake-build-environment provides options to configure the build. The followi
- **ASSIMP_NO_EXPORT (default OFF)**: Disable Assimp's export functionality.
- **ASSIMP_BUILD_ZLIB (default OFF)**: Build our own zlib.
- **ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all exporters enabled.
- **ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all importers enabled.
- **ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT (default ON)**: Build Assimp with (most) importers enabled. Currently, USD importer is not included. See ASSIMP_BUILD_USD_IMPORTER.
- **ASSIMP_BUILD_ASSIMP_TOOLS (default OFF)**: If the supplementary tools for Assimp are built in addition to the library.
- **ASSIMP_BUILD_SAMPLES (default OFF)**: If the official samples are built as well (needs Glut).
- **ASSIMP_BUILD_TESTS (default ON)**: If the test suite for Assimp is built in addition to the library.
@@ -83,6 +83,7 @@ The cmake-build-environment provides options to configure the build. The followi
- **USE_STATIC_CRT (default OFF)**: Link against the static MSVC runtime libraries.
- **ASSIMP_BUILD_DRACO (default OFF)**: Build Draco libraries. Primarily for glTF.
- **ASSIMP_BUILD_ASSIMP_VIEW (default ON, if DirectX found, OFF otherwise)**: Build Assimp view tool (requires DirectX).
- **ASSIMP_BUILD_USD_IMPORTER (default OFF, requires ASSIMP_WARNINGS_AS_ERRORS to be OFF)**: Build USD importer, defaults to off for CI purposes
### Install prebuild binaries
## Install on all platforms using vcpkg
@@ -109,5 +110,5 @@ You need to have pip installed:
pip install pyassimp
```
### Get the SDK from itchi.io
Just check [itchi.io](https://kimkulling.itch.io/the-asset-importer-lib)
### Get the SDK from itch.io
Just check [itch.io](https://kimkulling.itch.io/the-asset-importer-lib)
+1 -1
View File
@@ -591,7 +591,7 @@ ELSE()
SET(ASSIMP_BUILD_MINIZIP 1)
ELSE()
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
SET(ZLIB_LIBRARIES_LINKED -lz)
SET(ZLIB_LIBRARIES_LINKED -l${ZLIB_LIBRARIES})
ENDIF()
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
ENDIF()
+17
View File
@@ -0,0 +1,17 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "assimp_with_tools",
"binaryDir": "${sourceDir}",
"cacheVariables": {
"ASSIMP_BUILD_ASSIMP_TOOLS" : "ON"
}
}
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
+4 -4
View File
@@ -23,14 +23,14 @@ Additionally, assimp features various __mesh post-processing tools__: normals an
Read [our latest documentation](https://the-asset-importer-lib-documentation.readthedocs.io/en/latest/).
### Pre-built binaries ###
Download binaries from [our Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).
Download binaries from [our Itch Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).
### Test data ###
Clone [our model database](https://github.com/assimp/assimp-mdb).
Clone [our model database for testing purposes](https://github.com/assimp/assimp-mdb).
### Communities ###
- Ask questions at [the Assimp Discussion Board](https://github.com/assimp/assimp/discussions).
- Find us on [https://discord.gg/s9KJfaem](https://discord.gg/kKazXMXDy2)
- Find us on [discord](https://discord.gg/kKazXMXDy2)
- Ask [the 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)
@@ -83,7 +83,7 @@ The source code is organized in the following way:
code/AssetLib/<FormatName> Implementation for import and export of the format
### Contributing ###
I would greatly appreciate contributing to assimp. The easiest way to get involved is to submit
We would greatly appreciate for you to contribute to assimp. The easiest way to get involved is to submit
a pull request with your changes against the main repository's `master` branch.
## Contributors
+1 -2
View File
@@ -2,8 +2,7 @@
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
The current version of Assimp that's being supported with security updates:
| Version | Supported |
| ------- | ------------------ |
+1 -1
View File
@@ -319,7 +319,7 @@ void Discreet3DSImporter::ConvertMaterial(Material &oldMat, aiMaterial &mat) {
// ------------------------------------------------------------------------------------------------
// Split meshes by their materials and generate output aiMesh'es
void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
std::vector<aiMesh *> avOutMeshes;
MeshArray avOutMeshes;
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
unsigned int iFaceCnt = 0, num = 0;
+1 -1
View File
@@ -157,7 +157,7 @@ struct Component {
class Object : public Resource {
public:
std::vector<aiMesh *> mMeshes;
MeshArray mMeshes;
std::vector<unsigned int> mMeshIndex;
std::vector<Component> mComponents;
std::string mName;
+8 -6
View File
@@ -58,9 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map>
#include <vector>
namespace Assimp {
namespace Assimp::D3MF {
namespace D3MF {
// ------------------------------------------------------------------------------------------------
using OpcPackageRelationshipPtr = std::shared_ptr<OpcPackageRelationship>;
@@ -132,9 +131,11 @@ static bool IsEmbeddedTexture( const std::string &filename ) {
// ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr),
mZipArchive() {
mZipArchive(nullptr) {
mZipArchive = new ZipArchiveIOSystem(pIOHandler, rFile);
if (!mZipArchive->isOpen()) {
delete mZipArchive;
mZipArchive = nullptr;
throw DeadlyImportError("Failed to open file ", rFile, ".");
}
@@ -184,7 +185,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
}
D3MFOpcPackage::~D3MFOpcPackage() {
mZipArchive->Close(mRootStream);
if (mRootStream && mZipArchive) {
mZipArchive->Close(mRootStream);
}
delete mZipArchive;
}
@@ -250,7 +253,6 @@ void D3MFOpcPackage::LoadEmbeddedTextures(IOStream *fileStream, const std::strin
mEmbeddedTextures.emplace_back(texture);
}
} // Namespace D3MF
} // Namespace Assimp
} // Namespace Assimp::D3MF
#endif //ASSIMP_BUILD_NO_3MF_IMPORTER
+7 -1
View File
@@ -495,13 +495,16 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
}
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int vertex_index = 0; vertex_index < mesh->mNumVertices; vertex_index++) {
mesh->mTextureCoords[0][vertex_index].z = IdNotSet;//mark not set
mesh->mTextureCoords[0][vertex_index].z = IdNotSet; //mark not set
}
}
auto update_texture = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
if (vertex_index >= mesh->mNumVertices) {
return;
}
mesh->mTextureCoords[0][vertex_index] =
aiVector3D(group->mTex2dCoords[pindex[idx]].x, group->mTex2dCoords[pindex[idx]].y, 0.0f);
}
@@ -521,6 +524,9 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
auto update_color = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
if (vertex_index >= mesh->mNumVertices) {
return;
}
mesh->mColors[0][vertex_index] = group->mColors[pindex[idx]];
}
};
+41 -8
View File
@@ -75,6 +75,8 @@ static constexpr aiImporterDesc desc = {
"ac acc ac3d"
};
static constexpr auto ACDoubleSidedFlag = 0x20;
// ------------------------------------------------------------------------------------------------
// skip to the next token
inline const char *AcSkipToNextToken(const char *buffer, const char *end) {
@@ -123,12 +125,36 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end,
}
for (unsigned int _i = 0; _i < num; ++_i) {
buffer = AcSkipToNextToken(buffer, end);
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
buffer = fast_atoreal_move(buffer, ((float *)out)[_i]);
}
return buffer;
}
// ------------------------------------------------------------------------------------------------
// Reverses vertex indices in a face.
static void flipWindingOrder(aiFace &f) {
std::reverse(f.mIndices, f.mIndices + f.mNumIndices);
}
// ------------------------------------------------------------------------------------------------
// Duplicates a face and inverts it. Also duplicates all vertices (so the new face gets its own
// set of normals and isn’t smoothed against the original).
static void buildBacksideOfFace(const aiFace &origFace, aiFace *&outFaces, aiVector3D *&outVertices, const aiVector3D *allVertices,
aiVector3D *&outUV, const aiVector3D *allUV, unsigned &curIdx) {
auto &newFace = *outFaces++;
newFace = origFace;
flipWindingOrder(newFace);
for (unsigned f = 0; f < newFace.mNumIndices; ++f) {
*outVertices++ = allVertices[newFace.mIndices[f]];
if (outUV) {
*outUV = allUV[newFace.mIndices[f]];
outUV++;
}
newFace.mIndices[f] = curIdx++;
}
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
AC3DImporter::AC3DImporter() :
@@ -392,7 +418,7 @@ void AC3DImporter::ConvertMaterial(const Object &object,
// ------------------------------------------------------------------------------------------------
// Converts the loaded data to the internal verbose representation
aiNode *AC3DImporter::ConvertObjectSection(Object &object,
std::vector<aiMesh *> &meshes,
MeshArray &meshes,
std::vector<aiMaterial *> &outMaterials,
const std::vector<Material> &materials,
aiNode *parent) {
@@ -451,6 +477,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
if ((*it).entries.empty()) {
ASSIMP_LOG_WARN("AC3D: surface has zero vertex references");
}
const bool isDoubleSided = ACDoubleSidedFlag == (it->flags & ACDoubleSidedFlag);
const int doubleSidedFactor = isDoubleSided ? 2 : 1;
// validate all vertex indices to make sure we won't crash here
for (it2 = (*it).entries.begin(),
@@ -480,8 +508,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// triangle strip
case Surface::TriangleStrip:
needMat[idx].first += (unsigned int)(*it).entries.size() - 2;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3;
needMat[idx].first += static_cast<unsigned int>(it->entries.size() - 2) * doubleSidedFactor;
needMat[idx].second += static_cast<unsigned int>(it->entries.size() - 2) * 3 * doubleSidedFactor;
break;
default:
@@ -494,8 +522,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
case Surface::Polygon:
// the number of faces increments by one, the number
// of vertices by surface.numref.
needMat[idx].first++;
needMat[idx].second += (unsigned int)(*it).entries.size();
needMat[idx].first += doubleSidedFactor;
needMat[idx].second += static_cast<unsigned int>(it->entries.size()) * doubleSidedFactor;
};
}
unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes];
@@ -545,6 +573,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
for (it = object.surfaces.begin(); it != end; ++it) {
if (mat == (*it).mat) {
const Surface &src = *it;
const bool isDoubleSided = ACDoubleSidedFlag == (src.flags & ACDoubleSidedFlag);
// closed polygon
uint8_t type = (*it).GetType();
@@ -570,6 +599,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++uv;
}
}
if(isDoubleSided) // Need a backface?
buildBacksideOfFace(faces[-1], faces, vertices, mesh->mVertices, uv, mesh->mTextureCoords[0], cur);
}
} else if (type == Surface::TriangleStrip) {
for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
@@ -619,6 +650,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
uv->y = entry3.second.y;
++uv;
}
if(isDoubleSided) // Need a backface?
buildBacksideOfFace(faces[-1], faces, vertices, mesh->mVertices, uv, mesh->mTextureCoords[0], cur);
}
} else {
@@ -677,7 +710,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: ", object.name);
std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
MeshArray cpy(meshes.size() - oldm, nullptr);
div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
@@ -813,7 +846,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
}
mNumMeshes += (mNumMeshes >> 2u) + 1;
std::vector<aiMesh *> meshes;
MeshArray meshes;
meshes.reserve(mNumMeshes);
std::vector<aiMaterial *> omaterials;
+1 -1
View File
@@ -226,7 +226,7 @@ private:
* @param materials Material list
* @param Scenegraph node for the object */
aiNode *ConvertObjectSection(Object &object,
std::vector<aiMesh *> &meshes,
MeshArray &meshes,
std::vector<aiMaterial *> &outMaterials,
const std::vector<Material> &materials,
aiNode *parent = nullptr);
-2
View File
@@ -99,8 +99,6 @@ namespace Assimp {
///
class AMFImporter : public BaseImporter {
using AMFMetaDataArray = std::vector<AMFMetadata *>;
using MeshArray = std::vector<aiMesh *>;
using NodeArray = std::vector<aiNode *>;
public:
struct SPP_Material;
+3 -3
View File
@@ -162,7 +162,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
// process all meshes
bool tookNormals = false;
std::vector<aiMesh *> avOutMeshes;
MeshArray avOutMeshes;
avOutMeshes.reserve(mParser->m_vMeshes.size() * 2);
for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
if ((*i).bSkip) {
@@ -187,7 +187,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
// Now build the output mesh list. Remove dummies
pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
aiMesh **pp = pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (std::vector<aiMesh *>::const_iterator i = avOutMeshes.begin(); i != avOutMeshes.end(); ++i) {
for (MeshArray::const_iterator i = avOutMeshes.begin(); i != avOutMeshes.end(); ++i) {
if (!(*i)->mNumFaces) {
continue;
}
@@ -902,7 +902,7 @@ void ASEImporter::ConvertMaterial(ASE::Material &mat) {
// ------------------------------------------------------------------------------------------------
// Build output meshes
void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMeshes) {
void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, MeshArray &avOutMeshes) {
// validate the material index of the mesh
if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1;
+3 -3
View File
@@ -1427,7 +1427,7 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
// then parse the vertex weight
if (!SkipSpaces(&mFilePtr, mEnd)) break;
mFilePtr = fast_atoreal_move<float>(mFilePtr, pairOut.second);
mFilePtr = fast_atoreal_move(mFilePtr, pairOut.second);
// -1 marks unused entries
if (-1 != pairOut.first) {
@@ -1893,7 +1893,7 @@ void Parser::ParseLV4MeshReal(ai_real &fOut) {
return;
}
// parse the first float
mFilePtr = fast_atoreal_move<ai_real>(mFilePtr, fOut);
mFilePtr = fast_atoreal_move(mFilePtr, fOut);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloat(float &fOut) {
@@ -1906,7 +1906,7 @@ void Parser::ParseLV4MeshFloat(float &fOut) {
return;
}
// parse the first float
mFilePtr = fast_atoreal_move<float>(mFilePtr, fOut);
mFilePtr = fast_atoreal_move(mFilePtr, fOut);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLong(unsigned int &iOut) {
+1 -1
View File
@@ -385,7 +385,7 @@ float BVHLoader::GetNextTokenAsFloat() {
// check if the float is valid by testing if the atof() function consumed every char of the token
const char *ctoken = token.c_str();
float result = 0.0f;
ctoken = fast_atoreal_move<float>(ctoken, result);
ctoken = fast_atoreal_move(ctoken, result);
if (ctoken != token.c_str() + token.length())
ThrowException("Expected a floating point number, but found \"", token, "\".");
+3 -3
View File
@@ -961,7 +961,7 @@ void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/,
if (mesh->totface > static_cast<int>(mesh->mtface.size())) {
ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
for (MeshArray::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
@@ -1030,7 +1030,7 @@ void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/,
if (mesh->totface > static_cast<int>(mesh->tface.size())) {
ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
for (MeshArray::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
@@ -1057,7 +1057,7 @@ void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/,
if (mesh->totface > static_cast<int>((mesh->mcol.size() / 4))) {
ThrowException("Number of faces is larger than the corresponding color face array");
}
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
for (MeshArray::iterator it = temp->begin() + old; it != temp->end(); ++it) {
ai_assert(0 != (*it)->mNumVertices);
ai_assert(0 != (*it)->mNumFaces);
+8 -8
View File
@@ -166,10 +166,10 @@ void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
// copy meshes over
pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
std::copy(mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
// copy materials over, adding a default material if necessary
unsigned int mat_count = static_cast<unsigned int>(materials.size());
unsigned int mat_count = static_cast<unsigned int>(mMaterials.size());
for(aiMesh* mesh : meshes) {
ai_assert(mesh->mMaterialIndex <= mat_count);
if(mesh->mMaterialIndex >= mat_count) {
@@ -179,14 +179,14 @@ void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
const aiString name(AI_DEFAULT_MATERIAL_NAME);
def_material->AddProperty(&name, AI_MATKEY_NAME);
materials.push_back(def_material.release());
mMaterials.push_back(def_material.release());
break;
}
}
pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
std::copy(materials.begin(), materials.end(), pScene->mMaterials);
std::copy(mMaterials.begin(), mMaterials.end(), pScene->mMaterials);
}
// ------------------------------------------------------------------------------------------------
@@ -251,8 +251,8 @@ void C4DImporter::ReadMaterials(BaseMaterial* mat) {
while (mat) {
if (mat->GetType() == Mmaterial) {
aiMaterial* out = new aiMaterial();
material_mapping[mat] = static_cast<unsigned int>(materials.size());
materials.push_back(out);
mMaterialMapping[mat] = static_cast<unsigned int>(mMaterials.size());
mMaterials.push_back(out);
auto const ai_name = aiStringFrom(mat->GetName());
out->AddProperty(&ai_name, AI_MATKEY_NAME);
@@ -289,7 +289,7 @@ void C4DImporter::ReadMaterials(BaseMaterial* mat) {
// ------------------------------------------------------------------------------------------------
void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) {
ai_assert(parent != nullptr );
std::vector<aiNode*> nodes;
NodeArray nodes;
// based on Cineware sample code
while (object) {
@@ -577,7 +577,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) {
ai_assert(obj != nullptr);
const unsigned int mat_count = static_cast<unsigned int>(materials.size());
const unsigned int mat_count = static_cast<unsigned int>(mMaterials.size());
BaseTag* tag = obj->GetTag(Ttexture);
if(tag == nullptr) {
+5 -4
View File
@@ -97,11 +97,12 @@ private:
bool ReadShader(aiMaterial* out, cineware::BaseShader* shader);
std::vector<aiMesh*> meshes;
std::vector<aiMaterial*> materials;
private:
MeshArray mMeshes;
MaterialArray materials;
typedef std::map<cineware::BaseMaterial*, unsigned int> MaterialMap;
MaterialMap material_mapping;
using MaterialMap = std::map<cineware::BaseMaterial*, unsigned int> ;
MaterialMap mMaterialMapping;
}; // !class C4DImporter
+4 -4
View File
@@ -135,7 +135,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
else if (TokenMatchI(buffer,"rate",4)) {
SkipSpaces(&buffer, end);
float d = { 0.0f };
buffer = fast_atoreal_move<float>(buffer,d);
buffer = fast_atoreal_move(buffer,d);
anim->mTicksPerSecond = d;
}
else if (TokenMatchI(buffer,"order",5)) {
@@ -226,17 +226,17 @@ void CSMImporter::InternReadFile( const std::string& pFile,
} else {
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
sub->mTime = (double)frame;
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
buffer = fast_atoreal_move(buffer, sub->mValue.x);
if (!SkipSpacesAndLineEnd(&buffer, end)) {
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord");
}
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
buffer = fast_atoreal_move(buffer, sub->mValue.y);
if (!SkipSpacesAndLineEnd(&buffer, end)) {
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord");
}
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
buffer = fast_atoreal_move(buffer, sub->mValue.z);
++s->mNumPositionKeys;
}
+1 -1
View File
@@ -668,7 +668,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
}
// create morph target meshes if any
std::vector<aiMesh *> targetMeshes;
MeshArray targetMeshes;
std::vector<float> targetWeights;
Collada::MorphMethod method = Normalized;
+2 -2
View File
@@ -206,10 +206,10 @@ private:
std::map<std::string, size_t> mMaterialIndexByName;
/** Accumulated meshes for the target scene */
std::vector<aiMesh *> mMeshes;
MeshArray mMeshes;
/** Accumulated morph target meshes */
std::vector<aiMesh *> mTargetMeshes;
MeshArray mTargetMeshes;
/** Temporary material list */
std::vector<std::pair<Collada::Effect *, aiMaterial *>> newMats;
+11 -11
View File
@@ -129,7 +129,7 @@ static void ReadNodeTransformation(XmlNode &node, Node *pNode, TransformType pTy
// skip whitespace before the number
SkipSpacesAndLineEnd(&content, end);
// read a number
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
content = fast_atoreal_move(content, tf.f[a]);
}
// place the transformation at the queue of the node
@@ -346,13 +346,13 @@ static void ReadLight(XmlNode &node, Light &pLight) {
const char *content = v.c_str();
const char *end = content + v.size();
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
content = fast_atoreal_move(content, pLight.mColor.r);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
content = fast_atoreal_move(content, pLight.mColor.g);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
content = fast_atoreal_move(content, pLight.mColor.b);
SkipSpacesAndLineEnd(&content, end);
} else if (currentName == "constant_attenuation") {
XmlParser::getValueAsReal(currentNode, pLight.mAttConstant);
@@ -631,7 +631,7 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
std::string tUnitSizeString;
if (XmlParser::getStdStrAttribute(currentNode, "meter", tUnitSizeString)) {
try {
fast_atoreal_move<ai_real>(tUnitSizeString.data(), mUnitSize);
fast_atoreal_move(tUnitSizeString.data(), mUnitSize);
} catch (const DeadlyImportError& die) {
std::string warning("Collada: Failed to parse meter parameter to real number. Exception:\n");
warning.append(die.what());
@@ -889,7 +889,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
for (auto & a : controller.mBindShapeMatrix) {
SkipSpacesAndLineEnd(&content, end);
// read a number
content = fast_atoreal_move<ai_real>(content, a);
content = fast_atoreal_move(content, a);
// skip whitespace after it
SkipSpacesAndLineEnd(&content, end);
}
@@ -1262,16 +1262,16 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
const char *content = v.c_str();
const char *end = v.c_str() + v.size() + 1;
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
content = fast_atoreal_move(content, pColor.r);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.g);
content = fast_atoreal_move(content, pColor.g);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.b);
content = fast_atoreal_move(content, pColor.b);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.a);
content = fast_atoreal_move(content, pColor.a);
SkipSpacesAndLineEnd(&content, end);
} else if (currentName == "texture") {
// get name of source texture/sampler
@@ -1494,7 +1494,7 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
// read a number
ai_real value;
content = fast_atoreal_move<ai_real>(content, value);
content = fast_atoreal_move(content, value);
data.mValues.push_back(value);
// skip whitespace after it
SkipSpacesAndLineEnd(&content, end);
+3 -1
View File
@@ -91,7 +91,9 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
// ------------------------------------------------------------------------------------------------
size_t Offset(const char* begin, const char* cursor) {
ai_assert(begin <= cursor);
if (begin > cursor) {
return 0;
}
return cursor - begin;
}
+29 -30
View File
@@ -72,7 +72,7 @@ namespace FBX {
using namespace Util;
#define MAGIC_NODE_TAG "_$AssimpFbx$"
static constexpr char MAGIC_NODE_TAG[] = "_$AssimpFbx$";
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
@@ -125,21 +125,10 @@ static void correctRootTransform(const aiScene *scene) {
FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) :
defaultMaterialIndex(),
mMeshes(),
lights(),
cameras(),
textures(),
materials_converted(),
textures_converted(),
meshes_converted(),
node_anim_chain_bits(),
mNodeNames(),
anim_fps(),
mSceneOut(out),
doc(doc),
mRemoveEmptyBones(removeEmptyBones) {
// animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated.
@@ -162,7 +151,7 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
continue;
}
const Material *mat = dynamic_cast<const Material *>(ob);
auto mat = dynamic_cast<const Material *>(ob);
if (mat) {
if (materials_converted.find(mat) == materials_converted.end()) {
@@ -222,7 +211,6 @@ static std::string getAncestorBaseName(const aiNode *node) {
return std::string(nodeName, length);
}
// Make unique name
std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiNode &parent) {
std::string original_name = FixNodeName(model->Name());
if (original_name.empty()) {
@@ -236,9 +224,18 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
/// This struct manages nodes which may or may not end up in the node hierarchy.
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
struct FBXConverter::PotentialNode {
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; }
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {
// empty
}
explicit PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {
// empty
}
aiNode* operator->() {
return mNode;
}
std::unique_ptr<aiNode> mOwnership;
aiNode* mNode;
};
@@ -1092,14 +1089,14 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
}
static aiSkeleton *createAiSkeleton(SkeletonBoneContainer &sbc) {
if (sbc.MeshArray.empty() || sbc.SkeletonBoneToMeshLookup.empty()) {
if (sbc.meshArray.empty() || sbc.skeletonBoneToMeshLookup.empty()) {
return nullptr;
}
aiSkeleton *skeleton = new aiSkeleton;
for (auto *mesh : sbc.MeshArray) {
auto it = sbc.SkeletonBoneToMeshLookup.find(mesh);
if (it == sbc.SkeletonBoneToMeshLookup.end()) {
for (auto *mesh : sbc.meshArray) {
auto it = sbc.skeletonBoneToMeshLookup.find(mesh);
if (it == sbc.skeletonBoneToMeshLookup.end()) {
continue;
}
SkeletonBoneArray *ba = it->second;
@@ -1547,12 +1544,12 @@ static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *s
void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
std::vector<unsigned int> *outputVertStartIndices, SkeletonBoneContainer &skeletonContainer) {
if (skeletonContainer.SkeletonBoneToMeshLookup.find(out) != skeletonContainer.SkeletonBoneToMeshLookup.end()) {
if (skeletonContainer.skeletonBoneToMeshLookup.find(out) != skeletonContainer.skeletonBoneToMeshLookup.end()) {
return;
}
ConvertWeights(out, geo, absolute_transform, parent, materialIndex, outputVertStartIndices);
skeletonContainer.MeshArray.emplace_back(out);
skeletonContainer.meshArray.emplace_back(out);
SkeletonBoneArray *ba = new SkeletonBoneArray;
for (size_t i = 0; i < out->mNumBones; ++i) {
aiBone *bone = out->mBones[i];
@@ -1563,7 +1560,7 @@ void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo
copyBoneToSkeletonBone(out, bone, skeletonBone);
ba->emplace_back(skeletonBone);
}
skeletonContainer.SkeletonBoneToMeshLookup[out] = ba;
skeletonContainer.skeletonBoneToMeshLookup[out] = ba;
}
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
@@ -1571,8 +1568,6 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
std::vector<unsigned int> *outputVertStartIndices) {
ai_assert(geo.DeformerSkin());
std::vector<size_t> out_indices, index_out_indices, count_out_indices;
const Skin &sk = *geo.DeformerSkin();
std::vector<aiBone*> bones;
@@ -1580,6 +1575,10 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
ai_assert(no_mat_check || outputVertStartIndices);
try {
std::vector<size_t> count_out_indices;
std::vector<size_t> index_out_indices;
std::vector<size_t> out_indices;
// iterate over the sub deformers
for (const Cluster *cluster : sk.Clusters()) {
ai_assert(cluster);
@@ -1751,10 +1750,10 @@ unsigned int FBXConverter::GetDefaultMaterial() {
return defaultMaterialIndex - 1;
}
aiMaterial *out_mat = new aiMaterial();
auto out_mat = new aiMaterial();
materials.push_back(out_mat);
const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f);
const auto diffuse = aiColor3D(0.8f, 0.8f, 0.8f);
out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
aiString s;
@@ -1770,7 +1769,7 @@ unsigned int FBXConverter::ConvertMaterial(const Material &material, const MeshG
const PropertyTable &props = material.Props();
// generate empty output material
aiMaterial *out_mat = new aiMaterial();
auto out_mat = new aiMaterial();
materials_converted[&material] = static_cast<unsigned int>(materials.size());
materials.push_back(out_mat);
@@ -1809,7 +1808,7 @@ unsigned int FBXConverter::ConvertMaterial(const Material &material, const MeshG
unsigned int FBXConverter::ConvertVideo(const Video &video) {
// generate empty output texture
aiTexture *out_tex = new aiTexture();
auto out_tex = new aiTexture();
textures.push_back(out_tex);
// assuming the texture is compressed
+2 -2
View File
@@ -80,8 +80,8 @@ using SkeletonBoneArray = std::vector<aiSkeletonBone *>;
using SkeletonBoneToMesh = std::map<aiMesh*, SkeletonBoneArray*>;
struct SkeletonBoneContainer {
std::vector<aiMesh *> MeshArray;
SkeletonBoneToMesh SkeletonBoneToMeshLookup;
MeshArray meshArray;
SkeletonBoneToMesh skeletonBoneToMeshLookup;
};
class Document;
+60 -16
View File
@@ -365,10 +365,14 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
}
if (data[0] == 'F') {
return SafeParse<float>(data+1, t.end());
BE_NCONST float id = SafeParse<float>(data+1, t.end());
AI_SWAP4(id);
return id;
}
else {
return static_cast<float>( SafeParse<double>(data+1, t.end()) );
BE_NCONST double id = SafeParse<double>(data+1, t.end());
AI_SWAP8(id);
return static_cast<float>(id);
}
}
@@ -637,9 +641,15 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
if (type == 'd') {
const double* d = reinterpret_cast<const double*>(&buff[0]);
for (unsigned int i = 0; i < count3; ++i, d += 3) {
out.emplace_back(static_cast<ai_real>(d[0]),
static_cast<ai_real>(d[1]),
static_cast<ai_real>(d[2]));
BE_NCONST double val1 = d[0];
BE_NCONST double val2 = d[1];
BE_NCONST double val3 = d[2];
AI_SWAP8(val1);
AI_SWAP8(val2);
AI_SWAP8(val3);
out.emplace_back(static_cast<ai_real>(val1),
static_cast<ai_real>(val2),
static_cast<ai_real>(val3));
}
// for debugging
/*for ( size_t i = 0; i < out.size(); i++ ) {
@@ -652,7 +662,13 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
else if (type == 'f') {
const float* f = reinterpret_cast<const float*>(&buff[0]);
for (unsigned int i = 0; i < count3; ++i, f += 3) {
out.emplace_back(f[0],f[1],f[2]);
BE_NCONST float val1 = f[0];
BE_NCONST float val2 = f[1];
BE_NCONST float val3 = f[2];
AI_SWAP4(val1);
AI_SWAP4(val2);
AI_SWAP4(val3);
out.emplace_back(val1,val2,val3);
}
}
@@ -726,16 +742,32 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
if (type == 'd') {
const double* d = reinterpret_cast<const double*>(&buff[0]);
for (unsigned int i = 0; i < count4; ++i, d += 4) {
out.emplace_back(static_cast<float>(d[0]),
static_cast<float>(d[1]),
static_cast<float>(d[2]),
static_cast<float>(d[3]));
BE_NCONST double val1 = d[0];
BE_NCONST double val2 = d[1];
BE_NCONST double val3 = d[2];
BE_NCONST double val4 = d[3];
AI_SWAP8(val1);
AI_SWAP8(val2);
AI_SWAP8(val3);
AI_SWAP8(val4);
out.emplace_back(static_cast<float>(val1),
static_cast<float>(val2),
static_cast<float>(val3),
static_cast<float>(val4));
}
}
else if (type == 'f') {
const float* f = reinterpret_cast<const float*>(&buff[0]);
for (unsigned int i = 0; i < count4; ++i, f += 4) {
out.emplace_back(f[0],f[1],f[2],f[3]);
BE_NCONST float val1 = f[0];
BE_NCONST float val2 = f[1];
BE_NCONST float val3 = f[2];
BE_NCONST float val4 = f[3];
AI_SWAP4(val1);
AI_SWAP4(val2);
AI_SWAP4(val3);
AI_SWAP4(val4);
out.emplace_back(val1,val2,val3,val4);
}
}
return;
@@ -807,13 +839,21 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
if (type == 'd') {
const double* d = reinterpret_cast<const double*>(&buff[0]);
for (unsigned int i = 0; i < count2; ++i, d += 2) {
out.emplace_back(static_cast<float>(d[0]),
static_cast<float>(d[1]));
BE_NCONST double val1 = d[0];
BE_NCONST double val2 = d[1];
AI_SWAP8(val1);
AI_SWAP8(val2);
out.emplace_back(static_cast<float>(val1),
static_cast<float>(val2));
}
} else if (type == 'f') {
const float* f = reinterpret_cast<const float*>(&buff[0]);
for (unsigned int i = 0; i < count2; ++i, f += 2) {
out.emplace_back(f[0],f[1]);
BE_NCONST float val1 = f[0];
BE_NCONST float val2 = f[1];
AI_SWAP4(val1);
AI_SWAP4(val2);
out.emplace_back(val1,val2);
}
}
@@ -938,13 +978,17 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
if (type == 'd') {
const double* d = reinterpret_cast<const double*>(&buff[0]);
for (unsigned int i = 0; i < count; ++i, ++d) {
out.push_back(static_cast<float>(*d));
BE_NCONST double val = *d;
AI_SWAP8(val);
out.push_back(static_cast<float>(val));
}
}
else if (type == 'f') {
const float* f = reinterpret_cast<const float*>(&buff[0]);
for (unsigned int i = 0; i < count; ++i, ++f) {
out.push_back(*f);
BE_NCONST float val = *f;
AI_SWAP4(val);
out.push_back(val);
}
}
+3 -3
View File
@@ -162,7 +162,7 @@ aiMesh *IRRImporter::BuildSingleQuadMesh(const SkyboxVertex &v1,
}
// ------------------------------------------------------------------------------------------------
void IRRImporter::BuildSkybox(std::vector<aiMesh *> &meshes, std::vector<aiMaterial *> materials) {
void IRRImporter::BuildSkybox(MeshArray &meshes, std::vector<aiMaterial *> materials) {
// Update the material of the skybox - replace the name and disable shading for skyboxes.
for (unsigned int i = 0; i < 6; ++i) {
aiMaterial *out = (aiMaterial *)(*(materials.end() - (6 - i)));
@@ -602,7 +602,7 @@ void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis
// ------------------------------------------------------------------------------------------------
void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
BatchLoader &batch,
std::vector<aiMesh *> &meshes,
MeshArray &meshes,
std::vector<aiNodeAnim *> &anims,
std::vector<AttachmentInfo> &attach,
std::vector<aiMaterial *> &materials,
@@ -1283,7 +1283,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
std::vector<aiNodeAnim *> anims;
std::vector<aiMaterial *> materials;
std::vector<AttachmentInfo> attach;
std::vector<aiMesh *> meshes;
MeshArray meshes;
// try to guess how much storage we'll need
anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
+2 -2
View File
@@ -229,7 +229,7 @@ private:
/// Fill the scene-graph recursively
void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
BatchLoader &batch,
std::vector<aiMesh *> &meshes,
MeshArray &meshes,
std::vector<aiNodeAnim *> &anims,
std::vector<AttachmentInfo> &attach,
std::vector<aiMaterial *> &materials,
@@ -248,7 +248,7 @@ private:
/// @param meshes Receives 6 output meshes
/// @param materials The last 6 materials are assigned to the newly
/// created meshes. The names of the materials are adjusted.
void BuildSkybox(std::vector<aiMesh *> &meshes,
void BuildSkybox(MeshArray &meshes,
std::vector<aiMaterial *> materials);
// -------------------------------------------------------------------
+17 -17
View File
@@ -121,7 +121,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// final data
std::vector<aiMaterial *> materials;
std::vector<aiMesh *> meshes;
MeshArray meshes;
materials.reserve(5);
meshes.reserve(5);
@@ -433,24 +433,24 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, const char *end, Verte
aiColor4D c;
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
sz = fast_atoreal_move(sz, temp.z);
SkipSpaces(&sz, end);
vertices.push_back(temp);
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
sz = fast_atoreal_move(sz, temp.z);
SkipSpaces(&sz, end);
normals.push_back(temp);
@@ -466,10 +466,10 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, const char *end, Verte
SkipSpaces(&sz, end);
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
SkipSpaces(&sz, end);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
@@ -479,35 +479,35 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, const char *end, Verte
// So by definition, all buffers have either UV2 or tangents or neither
// read the (optional) second UV coordinate set
if (vertexFormat == VertexFormat::t2coord) {
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
temp.y = 1.f - temp.y; // DX to OGL
UV2s.push_back(temp);
}
// read optional tangent and bitangent vectors
else if (vertexFormat == VertexFormat::tangent) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
sz = fast_atoreal_move(sz, temp.z);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
SkipSpaces(&sz, end);
temp.y *= -1.0f;
tangents.push_back(temp);
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
sz = fast_atoreal_move(sz, temp.x);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
sz = fast_atoreal_move(sz, temp.z);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
sz = fast_atoreal_move(sz, temp.y);
SkipSpaces(&sz, end);
temp.y *= -1.0f;
bitangents.push_back(temp);
+3 -3
View File
@@ -139,21 +139,21 @@ void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vecto
const char *end = ptr + len;
SkipSpaces(&ptr, end);
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
ptr = fast_atoreal_move(ptr, out.value.x);
SkipSpaces(&ptr, end);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr, end);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
ptr = fast_atoreal_move(ptr, out.value.y);
SkipSpaces(&ptr, end);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr, end);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
ptr = fast_atoreal_move(ptr, out.value.z);
}
}
}
+1 -1
View File
@@ -239,7 +239,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
ResolveClips();
// now process all layers and build meshes and nodes
std::vector<aiMesh *> apcMeshes;
MeshArray apcMeshes;
std::map<uint16_t, aiNode *> apcNodes;
apcMeshes.reserve(mLayers->size() * std::min(((unsigned int)mSurfaces->size() / 2u), 1u));
+12 -12
View File
@@ -208,9 +208,9 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
float f;
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, key.value);
c = fast_atoreal_move(c, key.value);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, f);
c = fast_atoreal_move(c, f);
key.time = f;
@@ -242,7 +242,7 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
}
for (unsigned int i = 0; i < num; ++i) {
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, key.params[i]);
c = fast_atoreal_move(c, key.params[i]);
}
} else if ((*it).tokens[0] == "Behaviors") {
SkipSpaces(&c, end);
@@ -284,11 +284,11 @@ void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,c
// parse value and time, skip the rest for the moment.
LWO::Key key;
const char *c = fast_atoreal_move<float>((*it).tokens[0].c_str(), key.value);
const char *c = fast_atoreal_move((*it).tokens[0].c_str(), key.value);
const char *end = c + (*it).tokens[0].size();
SkipSpaces(&c, end);
float f;
fast_atoreal_move<float>((*it).tokens[0].c_str(), f);
fast_atoreal_move((*it).tokens[0].c_str(), f);
key.time = f;
envl.keys.emplace_back(key);
@@ -775,7 +775,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
ASSIMP_LOG_ERROR("LWS: envelopes for LightIntensity not supported, set to 1.0");
nodes.back().lightIntensity = (ai_real)1.0;
} else {
fast_atoreal_move<float>(c, nodes.back().lightIntensity);
fast_atoreal_move(c, nodes.back().lightIntensity);
}
}
}
@@ -816,11 +816,11 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
} else {
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.r);
c = fast_atoreal_move(c, nodes.back().lightColor.r);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.g);
c = fast_atoreal_move(c, nodes.back().lightColor.g);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.b);
c = fast_atoreal_move(c, nodes.back().lightColor.b);
}
}
@@ -829,11 +829,11 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (nodes.empty()) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
} else {
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.x);
c = fast_atoreal_move(c, nodes.back().pivotPos.x);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.y);
c = fast_atoreal_move(c, nodes.back().pivotPos.y);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.z);
c = fast_atoreal_move(c, nodes.back().pivotPos.z);
// Mark pivotPos as set
nodes.back().isPivotSet = true;
}
+8 -8
View File
@@ -246,11 +246,11 @@ inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *buf
return;
++*sz;
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.x);
*sz = fast_atoreal_move(*sz, vec.x);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.y);
*sz = fast_atoreal_move(*sz, vec.y);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.z);
*sz = fast_atoreal_move(*sz, vec.z);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
if (')' != **sz) {
MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber);
@@ -377,9 +377,9 @@ MD5MeshParser::MD5MeshParser(SectionArray &mSections) {
if ('(' != *sz++)
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.x);
sz = fast_atoreal_move(sz, vert.mUV.x);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.y);
sz = fast_atoreal_move(sz, vert.mUV.y);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
if (')' != *sz++)
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
@@ -415,7 +415,7 @@ MD5MeshParser::MD5MeshParser(SectionArray &mSections) {
WeightDesc &weight = desc.mWeights[idx];
weight.mBone = strtoul10(sz, &sz);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, weight.mWeight);
sz = fast_atoreal_move(sz, weight.mWeight);
AI_MD5_READ_TRIPLE(weight.vOffsetPosition, &sz, elem.end, elem.iLineNumber);
}
}
@@ -486,7 +486,7 @@ MD5AnimParser::MD5AnimParser(SectionArray &mSections) {
const char *sz = elem.szStart;
while (SkipSpacesAndLineEnd(&sz, elem.end)) {
float f;
sz = fast_atoreal_move<float>(sz, f);
sz = fast_atoreal_move(sz, f);
desc.mValues.push_back(f);
}
}
@@ -503,7 +503,7 @@ MD5AnimParser::MD5AnimParser(SectionArray &mSections) {
} else if ((*iter).mName == "numAnimatedComponents") {
mAnimatedBones.reserve(strtoul10((*iter).mGlobalValue.c_str()));
} else if ((*iter).mName == "frameRate") {
fast_atoreal_move<float>((*iter).mGlobalValue.c_str(), fFrameRate);
fast_atoreal_move((*iter).mGlobalValue.c_str(), fFrameRate);
}
}
ASSIMP_LOG_DEBUG("MD5AnimParser end");
+8 -2
View File
@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "MDLLoader.h"
#include "AssetLib/MD2/MD2FileData.h"
#include "HalfLife/HL1MDLLoader.h"
#include "HalfLife/HL1FileData.h"
#include "MDLDefaultColorMap.h"
#include <assimp/StringUtils.h>
@@ -1404,10 +1405,10 @@ void MDLImporter::InternReadFile_3DGS_MDL7() {
sharedData.apcOutBones = this->LoadBones_3DGS_MDL7();
// vector to held all created meshes
std::vector<aiMesh *> *avOutList;
MeshArray *avOutList;
// 3 meshes per group - that should be OK for most models
avOutList = new std::vector<aiMesh *>[pcHeader->groups_num];
avOutList = new MeshArray[pcHeader->groups_num];
for (uint32_t i = 0; i < pcHeader->groups_num; ++i)
avOutList[i].reserve(3);
@@ -1980,6 +1981,11 @@ void MDLImporter::InternReadFile_HL1(const std::string &pFile, const uint32_t iM
if (iMagicWord == AI_MDL_MAGIC_NUMBER_BE_HL2b || iMagicWord == AI_MDL_MAGIC_NUMBER_LE_HL2b)
throw DeadlyImportError("Impossible to properly load a model from an MDL sequence file.");
// Check if the buffer is large enough to hold the header
if (iFileSize < sizeof(HalfLife::Header_HL1)) {
throw DeadlyImportError("HL1 MDL file is too small to contain header.");
}
// Read the MDL file.
HalfLife::HL1MDLLoader loader(
pScene,
+1 -1
View File
@@ -86,7 +86,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_FLOAT(f) \
SkipSpaces(&sz, lineEnd); \
if (!IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
if (!IsLineEnd(*sz)) sz = fast_atoreal_move(sz, (ai_real &)f);
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_TRIPLE(v) \
+11 -11
View File
@@ -212,14 +212,14 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// stop at dimensions: this allows loading 1D or 2D coordinate vertices
for (unsigned int dim = 0; dim < dimensions; ++dim) {
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, *vec[dim]);
sz = fast_atoreal_move(sz, *vec[dim]);
}
// if has homogeneous coordinate, divide others by this one
if (hasHomogenous) {
SkipSpaces(&sz, lineEnd);
ai_real w = 1.;
sz = fast_atoreal_move<ai_real>(sz, w);
sz = fast_atoreal_move(sz, w);
for (unsigned int dim = 0; dim < dimensions; ++dim) {
*(vec[dim]) /= w;
}
@@ -229,11 +229,11 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (hasNormals) {
aiVector3D &n = mesh->mNormals[i];
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.x);
sz = fast_atoreal_move(sz, n.x);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.y);
sz = fast_atoreal_move(sz, n.y);
SkipSpaces(&sz, lineEnd);
fast_atoreal_move<ai_real>(sz, (ai_real &)n.z);
fast_atoreal_move(sz, n.z);
}
// reading colors is a pain because the specification says it can be
@@ -243,22 +243,22 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (hasColors) {
aiColor4D &c = mesh->mColors[0][i];
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.r);
sz = fast_atoreal_move(sz, c.r);
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.g);
sz = fast_atoreal_move(sz, c.g);
} else {
c.g = 0.;
}
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.b);
sz = fast_atoreal_move(sz, c.b);
} else {
c.b = 0.;
}
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.a);
sz = fast_atoreal_move(sz, c.a);
} else {
c.a = 1.;
}
@@ -266,9 +266,9 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (hasTexCoord) {
aiVector3D &t = mesh->mTextureCoords[0][i];
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)t.x);
sz = fast_atoreal_move(sz, t.x);
SkipSpaces(&sz, lineEnd);
fast_atoreal_move<ai_real>(sz, (ai_real &)t.y);
fast_atoreal_move(sz, t.y);
}
}
+5 -3
View File
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -396,9 +395,12 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
// ------------------------------------------------------------------------------------------------
void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices) {
if (nd == nullptr) {
return;
}
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
aiMesh *cm( nullptr );
aiMesh *cm{nullptr};
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
cm = pScene->mMeshes[nd->mMeshes[i]];
if (nullptr != cm) {
+27 -23
View File
@@ -165,21 +165,23 @@ struct Material {
//! Ambient color
aiColor3D ambient;
//! Diffuse color
aiColor3D diffuse;
aiColor3D diffuse = aiColor3D(0.6f, 0.6f, 0.6f);
//! Specular color
aiColor3D specular;
//! Emissive color
aiColor3D emissive;
//! Alpha value
ai_real alpha;
ai_real alpha = ai_real(1.0);
//! Shineness factor
ai_real shineness;
ai_real shineness = ai_real(0.0);
//! Illumination model
int illumination_model;
int illumination_model = 1;
//! Index of refraction
ai_real ior;
ai_real ior = ai_real(1.0);
//! Transparency color
aiColor3D transparent;
aiColor3D transparent = aiColor3D(1.0f, 1.0f, 1.0f);
//! Ambient occlusion
Maybe<ai_real> ambient_occlusion;
//! PBR Roughness
Maybe<ai_real> roughness;
@@ -187,31 +189,33 @@ struct Material {
Maybe<ai_real> metallic;
//! PBR Metallic
Maybe<aiColor3D> sheen;
//! PBR Sheen: an additional grazing component, primarily intended for cloth.
Maybe<ai_real> sheen_grazing;
//! PBR Sheen Tint: amount to tint sheen towards base color.
Maybe<ai_real> sheen_tint;
//! PBR Clearcoat
Maybe<ai_real> clearcoat;
//! PBR Clearcoat Thickness
Maybe<ai_real> clearcoat_thickness;
//! PBR Clearcoat Rougness
Maybe<ai_real> clearcoat_roughness;
//! PBR clearcoatGloss: controls clearcoat glossiness (0 = a “satin” appearance, 1 = a “gloss” appearance).
Maybe<ai_real> clearcoat_gloss;
//! PBR Anisotropy
ai_real anisotropy;
ai_real anisotropy = ai_real(0.0);
//! PBR Anisotropy Rotation
Maybe<ai_real> anisotropy_rotation;
//! PBR Subsurface Scattering
Maybe<ai_real> subsurface_scattering;
//! PBR Specular Tint: a concession for artistic control that tints incident specular towards the base color.
Maybe<ai_real> specular_tint;
// See: https://disneyanimation.com/publications/physically-based-shading-at-disney/
//! bump map multipler (normal map scalar)(-bm)
ai_real bump_multiplier;
//! bump map multiplier (normal map scalar)(-bm)
ai_real bump_multiplier = ai_real(1.0);
//! Constructor
Material() :
diffuse(0.6f, 0.6f, 0.6f),
alpha(ai_real(1.0)),
shineness(ai_real(0.0)),
illumination_model(1),
ior(ai_real(1.0)),
transparent(1.0f, 1.0, 1.0),
roughness(),
metallic(),
sheen(),
clearcoat_thickness(),
clearcoat_roughness(),
anisotropy(ai_real(0.0)),
bump_multiplier(ai_real(1.0)) {
Material() {
std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
}
+114 -8
View File
@@ -235,24 +235,64 @@ void ObjFileMtlImporter::load() {
++m_DataIt;
if (m_pModel->mCurrentMaterial != nullptr)
getFloatValue(m_pModel->mCurrentMaterial->clearcoat_roughness);
} else {
} else if (*m_DataIt == 't') {
++m_DataIt;
if (m_pModel->mCurrentMaterial != nullptr)
getFloatValue(m_pModel->mCurrentMaterial->clearcoat_thickness);
} else {
if (m_pModel->mCurrentMaterial != nullptr)
getFloatValue(m_pModel->mCurrentMaterial->clearcoat);
}
break;
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
}
break;
case 'm': // Texture or metallic
{
// Save start of token (after 'm')
auto tokenStart = m_DataIt; // points to 'm'
auto tokenEnd = getNextToken(m_DataIt, m_DataItEnd); // move iterator to end of token
std::string keyword(tokenStart, tokenEnd);
m_DataIt = tokenEnd; // advance iterator
if (keyword.compare(0, 3, "map") == 0) {
// starts with "map", treat as texture map
m_DataIt = tokenStart;
getTexture();
} else if (keyword == "metallic" || keyword == "metal" || keyword == "metalness") {
// parse metallic float value instead of texture
getFloatIfMaterialValid(&ObjFile::Material::metallic);
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 'm': // Texture
case 'b': // quick'n'dirty - for 'bump' sections
case 'r': // quick'n'dirty - for 'refl' sections
{
getTexture();
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 'r': // refl (map) or roughness (float)
{
auto tokenStart = m_DataIt; // points to 'r'
auto tokenEnd = getNextToken(m_DataIt, m_DataItEnd);
std::string keyword(tokenStart, tokenEnd);
m_DataIt = tokenEnd;
if (keyword == "roughness" || keyword == "rough") {
getFloatIfMaterialValid(&ObjFile::Material::roughness);
} else if (keyword == "refl" || keyword == "reflection") {
m_DataIt = tokenStart;
getTexture();
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 'i': // Illumination model
{
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
@@ -261,11 +301,60 @@ void ObjFileMtlImporter::load() {
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 'a': // Anisotropy
{
++m_DataIt;
if (m_pModel->mCurrentMaterial != nullptr)
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
case 'a': {
auto tokenStart = m_DataIt;
auto tokenEnd = getNextToken(m_DataIt, m_DataItEnd);
std::string keyword(tokenStart, tokenEnd);
m_DataIt = tokenEnd;
if (keyword == "aniso" || keyword == "anisotropy") {
getFloatIfMaterialValid(&ObjFile::Material::anisotropy);
} else if (keyword == "ao") {
getFloatIfMaterialValid(&ObjFile::Material::ambient_occlusion);
} else if (keyword == "anisor" || ai_stdStrToLower(keyword) == "anisotropicrotation") {
getFloatIfMaterialValid(&ObjFile::Material::anisotropy_rotation);
} else {
ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 's': {
auto tokenStart = m_DataIt;
auto tokenEnd = getNextToken(m_DataIt, m_DataItEnd);
std::string keyword(tokenStart, tokenEnd);
m_DataIt = tokenEnd;
if (keyword == "subsurface" || keyword == "scattering") {
getFloatIfMaterialValid(&ObjFile::Material::subsurface_scattering);
} else if (ai_stdStrToLower(keyword) == "speculartint") {
getFloatIfMaterialValid(&ObjFile::Material::specular_tint);
} else if (keyword == "sheen") {
getFloatIfMaterialValid(&ObjFile::Material::sheen_grazing);
} else if (ai_stdStrToLower(keyword) == "sheentint") {
getFloatIfMaterialValid(&ObjFile::Material::sheen_tint);
} else {
ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
case 'c': {
auto tokenStart = m_DataIt;
auto tokenEnd = getNextToken(m_DataIt, m_DataItEnd);
std::string keyword(tokenStart, tokenEnd);
m_DataIt = tokenEnd;
if (ai_stdStrToLower(keyword) == "clearcoat") {
getFloatIfMaterialValid(&ObjFile::Material::clearcoat);
} else if (ai_stdStrToLower(keyword) == "clearcoatgloss") {
getFloatIfMaterialValid(&ObjFile::Material::clearcoat_gloss);
} else {
ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
}
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
@@ -332,6 +421,23 @@ void ObjFileMtlImporter::getFloatValue(Maybe<ai_real> &value) {
value = Maybe<ai_real>();
}
// -------------------------------------------------------------------
// Writes a loaded single float value if material not null
void ObjFileMtlImporter::getFloatIfMaterialValid(ai_real ObjFile::Material::*member) {
if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) {
// This will call getFloatValue(ai_real&)
getFloatValue(m_pModel->mCurrentMaterial->*member);
}
}
// -------------------------------------------------------------------
void ObjFileMtlImporter::getFloatIfMaterialValid(Maybe<ai_real> ObjFile::Material::*member) {
// It can directly access `m_pModel` because it's part of the class
if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) {
getFloatValue(m_pModel->mCurrentMaterial->*member);
}
}
// -------------------------------------------------------------------
// Creates a material from loaded data.
void ObjFileMtlImporter::createMaterial() {
+2
View File
@@ -87,6 +87,8 @@ private:
/// Gets a float value from data.
void getFloatValue(ai_real &value);
void getFloatValue(Maybe<ai_real> &value);
void getFloatIfMaterialValid(ai_real ObjFile::Material::*member);
void getFloatIfMaterialValid(Maybe<ai_real> ObjFile::Material::*member);
/// Creates a new material from loaded data.
void createMaterial();
/// Get texture name from loaded data.
+7
View File
@@ -121,6 +121,13 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
m_DataItEnd = buffer.end();
mEnd = &buffer[buffer.size() - 1] + 1;
if (processed == 0 && std::distance(m_DataIt, m_DataItEnd) >= 3 &&
static_cast<unsigned char>(*m_DataIt) == 0xEF &&
static_cast<unsigned char>(*(m_DataIt + 1)) == 0xBB &&
static_cast<unsigned char>(*(m_DataIt + 2)) == 0xBF) {
m_DataIt += 3; // skip BOM
}
// Handle progress reporting
const size_t filePos(streamBuffer.getFilePos());
if (lastFilePos < filePos) {
+2 -2
View File
@@ -828,13 +828,13 @@ bool PLY::PropertyInstance::ParseValue(const char *&pCur,
// technically this should cast to float, but people tend to use float descriptors for double data
// this is the best way to not risk losing precision on import and it doesn't hurt to do this
ai_real f;
pCur = fast_atoreal_move<ai_real>(pCur, f);
pCur = fast_atoreal_move(pCur, f);
out->fFloat = (ai_real)f;
break;
case EDT_Double:
double d;
pCur = fast_atoreal_move<double>(pCur, d);
pCur = fast_atoreal_move(pCur, d);
out->fDouble = (double)d;
break;
+1 -1
View File
@@ -270,7 +270,7 @@ void Q3BSPFileImporter::CreateNodes(const Q3BSP::Q3BSPModel *pModel, aiScene *pS
}
unsigned int matIdx(0);
std::vector<aiMesh *> MeshArray;
MeshArray MeshArray;
std::vector<aiNode *> NodeArray;
for (FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) {
std::vector<Q3BSP::sQ3BSPFace *> *pArray = (*it).second;
+1 -1
View File
@@ -136,7 +136,7 @@ void RAWImporter::InternReadFile(const std::string &pFile,
unsigned int num;
for (num = 0; num < 12; ++num) {
if (!SkipSpaces(&sz, end) || !IsNumeric(*sz)) break;
sz = fast_atoreal_move<float>(sz, data[num]);
sz = fast_atoreal_move(sz, data[num]);
}
if (num != 12 && num != 9) {
ASSIMP_LOG_ERROR("A line may have either 9 or 12 floats and an optional texture");
+1 -1
View File
@@ -116,7 +116,7 @@ struct SIBObject {
struct SIB {
std::vector<aiMaterial *> mtls;
std::vector<aiMesh *> meshes;
MeshArray meshes;
std::vector<aiLight *> lights;
std::vector<SIBObject> objs, insts;
};
+1 -1
View File
@@ -982,7 +982,7 @@ bool SMDImporter::ParseFloat(const char *szCurrent, const char **szCurrentOut, c
return false;
}
*szCurrentOut = fast_atoreal_move<float>(szCurrent,out);
*szCurrentOut = fast_atoreal_move(szCurrent,out);
return true;
}
+1 -1
View File
@@ -404,7 +404,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
for(;*cur && *cur != ',' && *cur != ')' && !IsSpace(*cur);++cur) {
if (*cur == '.') {
double f;
inout = fast_atoreal_move<double>(start,f);
inout = fast_atoreal_move(start,f);
return std::make_shared<EXPRESS::REAL>(f);
}
}
+7 -7
View File
@@ -222,7 +222,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// ------------------------------------------------------------------------------------------------
// Read an ASCII STL file
void STLImporter::LoadASCIIFile(aiNode *root) {
std::vector<aiMesh *> meshes;
MeshArray meshes;
std::vector<aiNode *> nodes;
const char *sz = mBuffer;
const char *bufferEnd = mBuffer + mFileSize;
@@ -294,11 +294,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
aiVector3D vn;
sz += 7;
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.x);
sz = fast_atoreal_move(sz, vn.x);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.y);
sz = fast_atoreal_move(sz, vn.y);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.z);
sz = fast_atoreal_move(sz, vn.z);
normalBuffer.emplace_back(vn);
normalBuffer.emplace_back(vn);
normalBuffer.emplace_back(vn);
@@ -315,11 +315,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
SkipSpaces(&sz, bufferEnd);
positionBuffer.emplace_back();
aiVector3D *vn = &positionBuffer.back();
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
sz = fast_atoreal_move(sz, vn->x);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
sz = fast_atoreal_move(sz, vn->y);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->z);
sz = fast_atoreal_move(sz, vn->z);
faceVertexCounter++;
}
} else if (!::strncmp(sz, "endsolid", 8)) {
+3 -3
View File
@@ -383,11 +383,11 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
for (; !IsLineEnd(*data); ++data) {
if (data[0] == 'X' && data[1] == '=') {
data = fast_atoreal_move<float>(data + 2, (float &)nd->mTransformation.a1);
data = fast_atoreal_move(data + 2, nd->mTransformation.a1);
} else if (data[0] == 'Y' && data[1] == '=') {
data = fast_atoreal_move<float>(data + 2, (float &)nd->mTransformation.b2);
data = fast_atoreal_move(data + 2, nd->mTransformation.b2);
} else if (data[0] == 'Z' && data[1] == '=') {
data = fast_atoreal_move<float>(data + 2, (float &)nd->mTransformation.c3);
data = fast_atoreal_move(data + 2, nd->mTransformation.c3);
}
}
}
+1 -1
View File
@@ -219,7 +219,7 @@ void XFileImporter::CreateMeshes(aiScene *pScene, aiNode *pNode, const std::vect
}
// create a mesh for each mesh-material combination in the source node
std::vector<aiMesh *> meshes;
MeshArray meshes;
for (unsigned int a = 0; a < pMeshes.size(); ++a) {
XFile::Mesh *sourceMesh = pMeshes[a];
if (nullptr == sourceMesh) {
+1 -1
View File
@@ -1277,7 +1277,7 @@ ai_real XFileParser::ReadFloat() {
}
ai_real result = 0.0;
mP = fast_atoreal_move<ai_real>(mP, result);
mP = fast_atoreal_move(mP, result);
CheckForSeparator();
+10 -4
View File
@@ -128,13 +128,17 @@ void X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVec
#undef MESH_RectParallelepiped_CREATE_VERT
static constexpr int InvalidIndex = -1;
void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) {
std::vector<int32_t> f_data(pCoordIdx);
std::vector<unsigned int> inds;
unsigned int prim_type = 0;
if (f_data.back() != (-1)) {
f_data.push_back(-1);
if (!f_data.empty()) {
if (f_data.back() != InvalidIndex) {
f_data.push_back(InvalidIndex);
}
}
// reserve average size.
@@ -191,8 +195,10 @@ mg_m_err:
void X3DGeoHelper::coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces) {
std::vector<int32_t> f_data(pCoordIdx);
if (f_data.back() != (-1)) {
f_data.push_back(-1);
if (!f_data.empty()) {
if (f_data.back() != InvalidIndex) {
f_data.push_back(InvalidIndex);
}
}
// reserve average size.
+1 -1
View File
@@ -139,7 +139,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
ReadWorld(*worldNode, scope);
}
std::vector<aiMesh *> &meshes = scope.meshes_linear;
MeshArray &meshes = scope.meshes_linear;
std::vector<aiMaterial *> &materials = scope.materials_linear;
if (meshes.empty() || materials.empty()) {
ThrowException("failed to extract data from XGL file, no meshes loaded");
+1 -1
View File
@@ -192,7 +192,7 @@ static bool CheckValidFacesIndices(const aiFace *faces, unsigned nFaces, unsigne
}
void glTFImporter::ImportMeshes(Asset &r) {
std::vector<aiMesh *> meshes;
MeshArray meshes;
unsigned int k = 0;
meshOffsets.clear();
+16 -3
View File
@@ -59,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files, standard library.
#include <cinttypes>
#include <cmath>
#include <limits>
#include <memory>
#include <iostream>
@@ -1238,13 +1239,25 @@ void glTF2Exporter::ExportMeshes() {
}
/******************** Tangents ********************/
if (nullptr != aim->mTangents) {
if (nullptr != aim->mTangents && nullptr != aim->mBitangents) {
// Find the handedness by calculating the bitangent without the handedness factor,
// the use a dot product to find out if the original bitangent was inverted (multiplied
// by a factor of -1.0) or not (multiplied by 1.0)
std::vector<ai_real> tangentsWithHandedness(aim->mNumVertices * 4);
for (uint32_t i = 0; i < aim->mNumVertices; ++i) {
aiVector3D calculatedBitangent = aim->mNormals[i] ^ aim->mTangents[i];
ai_real bitangentDotProduct = calculatedBitangent * aim->mBitangents[i];
ai_real handedness = std::copysign(1.0, bitangentDotProduct);
aim->mTangents[i].NormalizeSafe();
tangentsWithHandedness[i * 4] = aim->mTangents[i][0];
tangentsWithHandedness[i * 4 + 1] = aim->mTangents[i][1];
tangentsWithHandedness[i * 4 + 2] = aim->mTangents[i][2];
tangentsWithHandedness[i * 4 + 3] = handedness;
}
Ref<Accessor> t = ExportData(
*mAsset, meshId, b, aim->mNumVertices, aim->mTangents, AttribType::VEC3,
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER
*mAsset, meshId, b, aim->mNumVertices, &tangentsWithHandedness[0], AttribType::VEC4,
AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER
);
if (t) {
p.attributes.tangent.push_back(t);
+15
View File
@@ -347,6 +347,21 @@ struct ReadHelper<int64_t> {
}
};
#ifdef __APPLE__
// On Mac size_t and uint64_t are not the same, so we need a specialized version
// here to properly parse byteOffset and other parameters > 2^31
// On Windows and Linux the types match andno additional specialization is required
template <>
struct ReadHelper<size_t> {
static bool Read(Value &val, size_t &out) {
return val.IsInt64() ? out = val.GetInt64(), true : false;
}
};
#endif
template <class T>
inline static bool ReadValue(Value &val, T &out) {
return ReadHelper<T>::Read(val, out);
-9
View File
@@ -740,8 +740,6 @@ SET( PostProcessing_SRCS
PostProcessing/GenFaceNormalsProcess.h
PostProcessing/GenVertexNormalsProcess.cpp
PostProcessing/GenVertexNormalsProcess.h
PostProcessing/GenerateMikkTSpaceTangents.cpp
PostProcessing/GenerateMikkTSpaceTangents.h
PostProcessing/PretransformVertices.cpp
PostProcessing/PretransformVertices.h
PostProcessing/ImproveCacheLocality.cpp
@@ -1172,12 +1170,6 @@ ENDIF()
SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS})
#ENDIF()
# mikktspacetangets
SET( MikkTSpaceTangents_SRCS
../contrib/MikkTSpace/mikktspace.c
../contrib/MikkTSpace/mikktspace.h
)
# minizip/unzip
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(minizip)
@@ -1375,7 +1367,6 @@ SET( assimp_src
${Tinyusdz_DEP_SOURCES}
${Pugixml_SRCS}
${stb_SRCS}
${MikkTSpaceTangents_SRCS}
# Necessary to show the headers in the project when using the VC++ generator:
${PUBLIC_HEADERS}
+13 -14
View File
@@ -678,8 +678,8 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
// ------------------------------------------------------------------------------------------------
// Build a list of unique bones
void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash> &asBones,
std::vector<aiMesh *>::const_iterator it,
std::vector<aiMesh *>::const_iterator end) {
MeshArray::const_iterator it,
MeshArray::const_iterator end) {
unsigned int iOffset = 0;
for (; it != end; ++it) {
for (unsigned int l = 0; l < (*it)->mNumBones; ++l) {
@@ -712,8 +712,7 @@ void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash> &asBones,
// ------------------------------------------------------------------------------------------------
// Merge a list of bones
void SceneCombiner::MergeBones(aiMesh *out, std::vector<aiMesh *>::const_iterator it,
std::vector<aiMesh *>::const_iterator end) {
void SceneCombiner::MergeBones(aiMesh *out, MeshArray::const_iterator it, MeshArray::const_iterator end) {
if (nullptr == out || out->mNumBones == 0) {
return;
}
@@ -771,8 +770,8 @@ void SceneCombiner::MergeBones(aiMesh *out, std::vector<aiMesh *>::const_iterato
// ------------------------------------------------------------------------------------------------
// Merge a list of meshes
void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
std::vector<aiMesh *>::const_iterator begin,
std::vector<aiMesh *>::const_iterator end) {
MeshArray::const_iterator begin,
MeshArray::const_iterator end) {
if (nullptr == _out) {
return;
}
@@ -788,7 +787,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
std::string name;
// Find out how much output storage we'll need
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
const char *meshName((*it)->mName.C_Str());
name += std::string(meshName);
if (it != end - 1) {
@@ -810,7 +809,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
if ((**begin).HasPositions()) {
pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
if ((*it)->mVertices) {
::memcpy(pv2, (*it)->mVertices, (*it)->mNumVertices * sizeof(aiVector3D));
} else
@@ -822,7 +821,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
if ((**begin).HasNormals()) {
pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
if ((*it)->mNormals) {
::memcpy(pv2, (*it)->mNormals, (*it)->mNumVertices * sizeof(aiVector3D));
} else {
@@ -837,7 +836,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
aiVector3D *pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
if ((*it)->mTangents) {
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices * sizeof(aiVector3D));
::memcpy(pv2b, (*it)->mBitangents, (*it)->mNumVertices * sizeof(aiVector3D));
@@ -854,7 +853,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
if ((*it)->mTextureCoords[n]) {
::memcpy(pv2, (*it)->mTextureCoords[n], (*it)->mNumVertices * sizeof(aiVector3D));
} else {
@@ -868,7 +867,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
n = 0;
while ((**begin).HasVertexColors(n)) {
aiColor4D *pVec2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
if ((*it)->mColors[n]) {
::memcpy(pVec2, (*it)->mColors[n], (*it)->mNumVertices * sizeof(aiColor4D));
} else {
@@ -887,7 +886,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
aiFace *pf2 = out->mFaces;
unsigned int ofs = 0;
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it) {
for (MeshArray::const_iterator it = begin; it != end; ++it) {
for (unsigned int m = 0; m < (*it)->mNumFaces; ++m, ++pf2) {
aiFace &face = (*it)->mFaces[m];
pf2->mNumIndices = face.mNumIndices;
@@ -910,7 +909,7 @@ void SceneCombiner::MergeMeshes(aiMesh **_out, unsigned int /*flags*/,
MergeBones(out, begin, end);
// delete all source meshes
for (std::vector<aiMesh *>::const_iterator it = begin; it != end; ++it)
for (MeshArray::const_iterator it = begin; it != end; ++it)
delete *it;
}
+3 -3
View File
@@ -158,8 +158,8 @@ void CatmullClarkSubdivider::Subdivide(
return;
}
std::vector<aiMesh *> inmeshes;
std::vector<aiMesh *> outmeshes;
MeshArray inmeshes;
MeshArray outmeshes;
std::vector<unsigned int> maptbl;
inmeshes.reserve(nmesh);
@@ -577,7 +577,7 @@ void CatmullClarkSubdivider::InternSubdivide(
// 7. Apply the next subdivision step.
// ---------------------------------------------------------------------
if (num != 1) {
std::vector<aiMesh *> tmp(nmesh);
MeshArray tmp(nmesh);
InternSubdivide(out, nmesh, &tmp.front(), num - 1);
for (size_t i = 0; i < nmesh; ++i) {
delete out[i];
+1 -1
View File
@@ -159,7 +159,7 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
ai_assert(prop->mDataLength >= 5);
ai_assert(!prop->mData[prop->mDataLength - 1]);
for (unsigned int a = 0;; ++a) {
cur = fast_atoreal_move<TReal>(cur, pOut[a]);
cur = fast_atoreal_move(cur, pOut[a]);
if (a == iWrite - 1) {
break;
}
+3 -7
View File
@@ -5,6 +5,8 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -61,11 +63,7 @@ CalcTangentsProcess::CalcTangentsProcess() :
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
const bool active = ((pFlags & aiProcess_CalcTangentSpace) != 0);
if (mActive) {
return active;
}
return false;
return (pFlags & aiProcess_CalcTangentSpace) != 0;
}
// ------------------------------------------------------------------------------------------------
@@ -73,8 +71,6 @@ bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
ai_assert(nullptr != pImp);
mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false);
// get the current value of the property
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
@@ -102,7 +102,6 @@ private:
/** Configuration option: maximum smoothing angle, in radians*/
float configMaxAngle;
unsigned int configSourceUV;
bool mActive = true;
};
} // end of namespace Assimp
@@ -1,99 +0,0 @@
#include "GenerateMikkTSpaceTangents.h"
#include <assimp/scene.h>
#include <assimp/postprocess.h>
namespace Assimp {
static int get_num_faces(const SMikkTSpaceContext *context);
static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace);
static void get_position(const SMikkTSpaceContext *context, float outpos[], int iFace, int iVert);
static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int iFace, int iVert);
static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int iFace, int iVert);
static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float fSign, int iFace, int iVert);
static int get_num_faces(const SMikkTSpaceContext *context) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const int numFaces = static_cast<int>(currentMesh->mNumFaces);
return numFaces;
}
static int get_num_vertices_of_face(const SMikkTSpaceContext *context, int iFace) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiFace &face = currentMesh->mFaces[iFace];
return face.mNumIndices;
}
static void get_position(const SMikkTSpaceContext *context, float outpos[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiVector3D &v = currentMesh->mVertices[static_cast<size_t>(iVert)];
outpos[0] = v.x;
outpos[1] = v.y;
outpos[2] = v.z;
}
static void get_normal(const SMikkTSpaceContext *context, float outnormal[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
const aiVector3D &n = currentMesh->mNormals[static_cast<size_t>(iVert)];
outnormal[0] = n.x;
outnormal[1] = n.y;
outnormal[2] = n.z;
}
static void get_tex_coords(const SMikkTSpaceContext *context, float outuv[], int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
aiVector3D &t = currentMesh->mTextureCoords[static_cast<size_t>(iVert)][0];
if (currentMesh->mNumUVComponents[iVert] == 2) {
outuv[0] = t.x;
outuv[1] = t.y;
} else if (currentMesh->mNumUVComponents[iVert] == 3){
outuv[0] = t.x;
outuv[1] = t.y;
outuv[2] = 0.0;
}
}
static void set_tspace_basic(const SMikkTSpaceContext *context, const float tangentu[], float /*fSign*/, int /*iFace*/, int iVert) {
const aiMesh *currentMesh = static_cast<aiMesh*>(context->m_pUserData);
currentMesh->mTangents[iVert].x = tangentu[0];
currentMesh->mTangents[iVert].y = tangentu[1];
currentMesh->mTangents[iVert].z = tangentu[2];
}
bool GenerateMikkTSpaceTangents::IsActive(unsigned int pFlags) const {
const bool active = (pFlags & aiProcess_CalcTangentSpace) != 0;
if (mActive) {
return active;
}
return false;
}
void GenerateMikkTSpaceTangents::Execute(aiScene* pScene) {
mIface.m_getNumFaces = get_num_faces;
mIface.m_getNumVerticesOfFace = get_num_vertices_of_face;
mIface.m_getNormal = get_normal;
mIface.m_getPosition = get_position;
mIface.m_getTexCoord = get_tex_coords;
mIface.m_setTSpaceBasic = set_tspace_basic;
mContext.m_pInterface = &mIface;
for (size_t i=0; i<pScene->mNumMeshes; ++i) {
aiMesh *mesh = pScene->mMeshes[i];
ExecutePerMesh(mesh);
}
}
void GenerateMikkTSpaceTangents::SetupProperties(const Importer *pImp) {
mActive = pImp->GetPropertyBool(AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS, false);
}
void GenerateMikkTSpaceTangents::ExecutePerMesh(aiMesh *mesh) {
if (mesh == nullptr) {
return;
}
mContext.m_pUserData = mesh;
genTangSpaceDefault(&mContext);
}
} // namespace Assimp
@@ -1,25 +0,0 @@
#pragma once
#include "Common/BaseProcess.h"
#include "contrib/MikkTSpace/mikktspace.h"
struct aiMesh;
namespace Assimp {
class GenerateMikkTSpaceTangents final : public BaseProcess {
public:
GenerateMikkTSpaceTangents() = default;
~GenerateMikkTSpaceTangents() override = default;
bool IsActive(unsigned int pFlags) const override;
void Execute(aiScene* pScene) override;
void SetupProperties(const Importer *pImp) override;
void ExecutePerMesh(aiMesh *mesh);
private:
bool mActive = false;
SMikkTSpaceInterface mIface;
SMikkTSpaceContext mContext;
};
} // namespace Assimp
+60 -1
View File
@@ -100,6 +100,65 @@ void JoinVerticesProcess::Execute( aiScene* pScene) {
namespace {
struct CompareVerticesAlmostEqual {
bool operator () (const Vertex & a, const Vertex & b) const {
static const float epsilon = 1e-5f;
static const float squareEpsilon = epsilon * epsilon;
if ((a.position - b.position).SquareLength() > squareEpsilon) {
return false;
}
// We just test the other attributes even if they're not present in the mesh.
// In this case they're initialized to 0 so the comparison succeeds.
// By this method the non-present attributes are effectively ignored in the comparison.
if ((a.normal - b.normal).SquareLength() > squareEpsilon) {
return false;
}
if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) {
return false;
}
if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) {
return false;
}
for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) {
return false;
}
}
for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) {
return false;
}
}
// If reached this point, they are ~equal
return true;
}
};
struct HashVertex {
inline void hash_combine(std::size_t& seed, const ai_real& v) const {
std::hash<ai_real> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
size_t operator () (const Vertex & v) const {
size_t hash = 0;
hash_combine(hash, v.position.x);
hash_combine(hash, v.position.y);
hash_combine(hash, v.position.z);
return hash;
}
};
template<class XMesh>
void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
// replace vertex data with the unique data sets
@@ -208,7 +267,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
}
}
// a map that maps a vertex to its new index
std::map<Vertex, int> vertex2Index = {};
std::unordered_map<Vertex, int, HashVertex, CompareVerticesAlmostEqual> vertex2Index = {};
// we can not end up with more vertices than we started with
// Now check each vertex if it brings something new to the table
int newIndex = 0;
+2 -2
View File
@@ -332,7 +332,7 @@ void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat)
// ------------------------------------------------------------------------------------------------
// Simple routine to build meshes in worldspace, no further optimization
void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
void PretransformVertices::BuildWCSMeshes(MeshArray &out, aiMesh **in,
unsigned int numIn, aiNode *node) const {
// NOTE:
// aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
@@ -459,7 +459,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
}
// now build a list of output meshes
std::vector<aiMesh *> apcOutMeshes;
MeshArray apcOutMeshes;
// Keep scene hierarchy? It's an easy job in this case ...
// we go on and transform all meshes, if one is referenced by nodes
+1 -1
View File
@@ -139,7 +139,7 @@ private:
// -------------------------------------------------------------------
// Simple routine to build meshes in worldspace, no further optimization
void BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
void BuildWCSMeshes(MeshArray &out, aiMesh **in,
unsigned int numIn, aiNode *node) const;
// -------------------------------------------------------------------
+6 -2
View File
@@ -126,7 +126,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
std::vector<aiMesh *> outMeshes;
MeshArray outMeshes;
outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
bool bAnyChanges = false;
@@ -165,6 +165,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
*meshIdx = static_cast<unsigned int>(outMeshes.size());
outMeshes.emplace_back(mesh);
pScene->mMeshes[i] = nullptr; // Indicate ownership transfer
} else {
delete mesh;
pScene->mMeshes[i] = nullptr;
@@ -188,12 +189,15 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
unsigned int numPolyVerts = 0;
for (; pFirstFace != pLastFace; ++pFirstFace) {
if (pFirstFace->mNumIndices <= 3)
if (pFirstFace->mNumIndices >= 1 && pFirstFace->mNumIndices <= 3)
++aiNumPerPType[pFirstFace->mNumIndices - 1];
else {
++aiNumPerPType[3];
numPolyVerts += pFirstFace->mNumIndices;
}
if (pFirstFace->mNumIndices == 0) {
ASSIMP_LOG_WARN("Face with 0 indices treated as polygon");
}
}
VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh);
File diff suppressed because it is too large Load Diff
-145
View File
@@ -1,145 +0,0 @@
/** \file mikktspace/mikktspace.h
* \ingroup mikktspace
*/
/**
* Copyright (C) 2011 by Morten S. Mikkelsen
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef __MIKKTSPACE_H__
#define __MIKKTSPACE_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Author: Morten S. Mikkelsen
* Version: 1.0
*
* The files mikktspace.h and mikktspace.c are designed to be
* stand-alone files and it is important that they are kept this way.
* Not having dependencies on structures/classes/libraries specific
* to the program, in which they are used, allows them to be copied
* and used as is into any tool, program or plugin.
* The code is designed to consistently generate the same
* tangent spaces, for a given mesh, in any tool in which it is used.
* This is done by performing an internal welding step and subsequently an order-independent evaluation
* of tangent space for meshes consisting of triangles and quads.
* This means faces can be received in any order and the same is true for
* the order of vertices of each face. The generated result will not be affected
* by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
* primitives are present or not will not affect the generated results either.
* Once tangent space calculation is done the vertices of degenerate primitives will simply
* inherit tangent space from neighboring non degenerate primitives.
* The analysis behind this implementation can be found in my master's thesis
* which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
* Note that though the tangent spaces at the vertices are generated in an order-independent way,
* by this implementation, the interpolated tangent space is still affected by which diagonal is
* chosen to split each quad. A sensible solution is to have your tools pipeline always
* split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
* If these have the same length then compare the diagonals defined by the texture coordinates.
* XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
* and also quad triangulator plugin.
*/
typedef int tbool;
typedef struct SMikkTSpaceContext SMikkTSpaceContext;
typedef struct {
// Returns the number of faces (triangles/quads) on the mesh to be processed.
int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
// Returns the number of vertices on face number iFace
// iFace is a number in the range {0, 1, ..., getNumFaces()-1}
int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace);
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
// either (or both) of the two setTSpace callbacks can be set.
// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
// This function is used to return the tangent and fSign to the application.
// fvTangent is a unit length vector.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
// This function is used to return tangent space results to the application.
// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
// true magnitudes which can be used for relief mapping effects.
// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
// However, both are perpendicular to the vertex normal.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
} SMikkTSpaceInterface;
struct SMikkTSpaceContext
{
SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
};
// these are both thread safe!
tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold);
// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
// normal map sampler must use the exact inverse of the pixel shader transformation.
// The most efficient transformation we can possibly do in the pixel shader is
// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
// pixel shader (fast transform out)
// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
// where vNt is the tangent space normal. The normal map sampler must likewise use the
// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
// sampler does (exact inverse of pixel shader):
// float3 row0 = cross(vB, vN);
// float3 row1 = cross(vN, vT);
// float3 row2 = cross(vT, vB);
// float fSign = dot(vT, row0)<0 ? -1 : 1;
// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
// where vNout is the sampled normal in some chosen 3D space.
//
// Should you choose to reconstruct the bitangent in the pixel shader instead
// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
// However, this must be used both by the sampler and your tools/rendering pipeline.
#ifdef __cplusplus
}
#endif
#endif
+12 -6
View File
@@ -583,6 +583,9 @@ char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueTyp
size_t prim_len(0);
for (size_t i = 0; i < (size_t) Value::ValueType::ddl_types_max; i++) {
prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
if (static_cast<size_t>(end - in) < prim_len) {
continue;
}
if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
type = static_cast<Value::ValueType>(i);
break;
@@ -595,6 +598,9 @@ char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueTyp
} else {
in += prim_len;
}
if (in >= end) {
return in;
}
bool ok(true);
if (*in == Grammar::OpenArrayToken[0]) {
@@ -602,13 +608,13 @@ char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueTyp
++in;
char *start(in);
while (in != end) {
++in;
if (*in == Grammar::CloseArrayToken[0]) {
len = ::atoi(start);
ok = true;
++in;
break;
}
++in;
}
} else {
len = 1;
@@ -630,9 +636,9 @@ char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &na
if (nextName) {
names.push_back(nextName);
}
while (Grammar::CommaSeparator[0] == *in) {
while (in != end && Grammar::CommaSeparator[0] == *in) {
in = getNextSeparator(in, end);
if (Grammar::CommaSeparator[0] == *in) {
if (in != end && Grammar::CommaSeparator[0] == *in) {
in = parseName(in, end, &nextName);
if (nextName) {
names.push_back(nextName);
@@ -655,7 +661,7 @@ char *OpenDDLParser::parseBooleanLiteral(char *in, char *end, Value **boolean) {
char *start(in);
size_t len(0);
while (!isSeparator(*in) && in != end) {
while (in != end && !isSeparator(*in)) {
++in;
++len;
}
@@ -688,7 +694,7 @@ char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, V
in = lookForNextToken(in, end);
char *start(in);
while (!isSeparator(*in) && in != end) {
while (in != end && !isSeparator(*in)) {
++in;
}
@@ -831,7 +837,7 @@ char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
bool ok(true);
char *start(in);
int pos(0);
while (!isSeparator(*in) && in != end) {
while (in != end && !isSeparator(*in)) {
if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
ok = false;
break;
+1 -1
View File
@@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2025, assimp team
All rights reserved.
+2
View File
@@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h>
#include <exception>
#include <vector>
namespace Assimp {
// =======================================================================
@@ -67,6 +68,7 @@ class IOStream;
class IOSystem;
class ProgressHandler;
// =======================================================================
// Plugin development
//
+6 -6
View File
@@ -240,8 +240,8 @@ public:
* @param end Points to the mesh after the last mesh to be processed
*/
static void MergeMeshes(aiMesh **dest, unsigned int flags,
std::vector<aiMesh *>::const_iterator begin,
std::vector<aiMesh *>::const_iterator end);
MeshArray::const_iterator begin,
MeshArray::const_iterator end);
// -------------------------------------------------------------------
/** Merges two or more bones
@@ -251,8 +251,8 @@ public:
* @param begin First mesh to be processed
* @param end Points to the mesh after the last mesh to be processed
*/
static void MergeBones(aiMesh *out, std::vector<aiMesh *>::const_iterator it,
std::vector<aiMesh *>::const_iterator end);
static void MergeBones(aiMesh *out, MeshArray::const_iterator it,
MeshArray::const_iterator end);
// -------------------------------------------------------------------
/** Merges two or more materials
@@ -277,8 +277,8 @@ public:
* @param end Last mesh to be processed
*/
static void BuildUniqueBoneList(std::list<BoneWithHash> &asBones,
std::vector<aiMesh *>::const_iterator it,
std::vector<aiMesh *>::const_iterator end);
MeshArray::const_iterator it,
MeshArray::const_iterator end);
// -------------------------------------------------------------------
/** Add a name prefix to all nodes in a scene.
-23
View File
@@ -183,29 +183,6 @@ struct Vertex {
return *this;
}
bool operator < (const Vertex & o) const {
if (position < o.position) return true;
if (position != o.position) return false;
if (normal < o.normal) return true;
if (normal != o.normal) return false;
for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
if (texcoords[i] < o.texcoords[i]) return true;
if (texcoords[i] != o.texcoords[i]) return false;
}
// note that tangent/bitangent are not checked since they are optional
for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
if (colors[i] < o.colors[i]) return true;
if (colors[i] != o.colors[i]) return false;
}
// if reached this point, they are equal
return false;
}
// ----------------------------------------------------------------------------
/// Convert back to non-interleaved storage
void SortBack(aiMesh* out, unsigned int idx) const {
+1 -4
View File
@@ -1175,9 +1175,6 @@ enum aiComponent
#endif // AI_CONFIG_APP_SCALE_KEY
#define AI_CONFIG_POSTPROCESS_USE_MIKKTSPACE_TANGENTS \
"POSTPROCESS_USE_MIKKTSPACE_TANGENTS"
// ---------- All the Build/Compile-time defines ------------
/** @brief Specifies if double precision is supported inside assimp
@@ -1185,6 +1182,6 @@ enum aiComponent
* Property type: Bool. Default value: undefined.
*/
#define ASSIMP_DOUBLE_PRECISION 1
#cmakedefine ASSIMP_DOUBLE_PRECISION 1
#endif // !! AI_CONFIG_H_INC
+1
View File
@@ -1174,3 +1174,4 @@ struct aiSkeleton {
#endif //! extern "C"
#endif // AI_MESH_H_INC
+12
View File
@@ -70,9 +70,15 @@ union _IEEESingle {
float Float;
struct
{
#if (defined AI_BUILD_BIG_ENDIAN)
uint32_t Sign : 1;
uint32_t Exp : 8;
uint32_t Frac : 23;
#else
uint32_t Frac : 23;
uint32_t Exp : 8;
uint32_t Sign : 1;
#endif
} IEEE;
};
@@ -83,9 +89,15 @@ union _IEEEDouble {
double Double;
struct
{
#if (defined AI_BUILD_BIG_ENDIAN)
uint64_t Sign : 1;
uint64_t Exp : 11;
uint64_t Frac : 52;
#else
uint64_t Frac : 52;
uint64_t Exp : 11;
uint64_t Sign : 1;
#endif
} IEEE;
};
+11
View File
@@ -77,6 +77,17 @@ typedef uint32_t ai_uint32;
#include <new> // for std::nothrow_t
#include <string> // for aiString::Set(const std::string&)
struct aiNode;
struct aiMesh;
struct aiMaterial;
#include <vector>
using MeshArray = std::vector<aiMesh *>;
using NodeArray = std::vector<aiNode *>;
using MaterialArray = std::vector<aiMaterial*>;
namespace Assimp {
//! @cond never
namespace Intern {
+5 -5
View File
@@ -2,7 +2,7 @@
[Setup]
AppName=Open Asset Import Library - SDK
AppVerName=Open Asset Import Library - SDK (v5.4.3)
AppVerName=Open Asset Import Library - SDK (v6.0.2)
DefaultDirName={pf}\Assimp
DefaultGroupName=Assimp
UninstallDisplayIcon={app}\bin\x64\assimp.exe
@@ -12,9 +12,9 @@ SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico
WizardImageFile=..\..\tools\shared\assimp_tools_icon.bmp
WizardSmallImageFile=..\..\tools\shared\assimp_tools_icon.bmp
LicenseFile=License.rtf
OutputBaseFileName=assimp-sdk-5.4.3-setup
VersionInfoVersion=5.4.3.0
VersionInfoTextVersion=5.4.3
OutputBaseFileName=assimp-sdk-6.0.2-setup
VersionInfoVersion=6.0.2.0
VersionInfoTextVersion=6.0.2
VersionInfoCompany=Assimp Development Team
ArchitecturesInstallIn64BitMode=x64
@@ -43,7 +43,7 @@ Source: "vc_redist.x64.exe"; DestDir: "{app}\stub\"; Check: IsWin64
; Common stuff
Source: "..\..\CREDITS"; DestDir: "{app}"
Source: "..\..\LICENSE"; DestDir: "{app}"
Source: "..\..\README"; DestDir: "{app}"
Source: "..\..\README.md"; DestDir: "{app}"
Source: "WEB"; DestDir: "{app}"
Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs
+13 -5
View File
@@ -36,13 +36,21 @@ aiProcess_JoinIdenticalVertices = 0x2
#
aiProcess_MakeLeftHanded = 0x4
## <hr>Triangulates all faces of all meshes.
## <hr>Triangulates all faces of all meshes.
#
# By default the imported mesh data might contain faces with more than 3
# indices. For rendering you'll usually want all faces to be triangles.
# This post processing stepaiProcess_ForceGenNormals
## <hr>Removes some parts of the data structure (animations, materials,
# light sources, cameras, textures, vertex components).
# indices. For rendering you'll usually want all faces to be triangles.
# This post processing step splits up faces with more than 3 indices into
# triangles. Line and point primitives are *not* modified! If you want
# 'triangles only' with no other kinds of primitives, try the following
# solution:
# - Specify both #aiProcess_Triangulate and #aiProcess_SortByPType
# - Ignore all point and line meshes when you process assimp's output
#
aiProcess_Triangulate = 0x8
# <hr>Removes some parts of the data structure (animations, materials,
# light sources, cameras, textures, vertex components).
#
# The components to be removed are specified in a separate
# configuration option, <tt>#AI_CONFIG_PP_RVC_FLAGS<tt>. This is quite useful
+1 -1
View File
@@ -314,7 +314,7 @@ public final class AiMesh {
* @return true if tangents and bitangents are available
*/
public boolean hasTangentsAndBitangents() {
return m_tangents != null && m_tangents != null;
return m_tangents != null && m_bitangents != null;
}
+21
View File
@@ -0,0 +1,21 @@
AC3Db
MATERIAL "" rgb 1 1 1 amb 0.2 0.2 0.2 emis 0 0 0 spec 0.5 0.5 0.5 shi 10 trans 0
OBJECT world
kids 1
OBJECT poly
name "rect"
loc 1 0.5 0
numvert 4
-1 0.5 0
1 0.5 0
1 -0.5 0
-1 -0.5 0
numsurf 1
SURF 0x20
mat 0
refs 4
3 0 0
2 1 0
1 1 1
0 0 1
kids 0
+11
View File
@@ -141,3 +141,14 @@ TEST(utACImportExport, testFormatDetection) {
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AC/TestFormatDetection", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, scene);
}
TEST(utACImportExport, importDobuleSidedFaces) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AC/doubleSidedFace.ac", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, scene);
// The scene contains one double-sided, rectangular AC surface. It should resolve to two quads (front + back) with eight
// vertices (one per side to guarantee proper normal vectors).
ASSERT_EQ(scene->mNumMeshes, 1u);
ASSERT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
ASSERT_EQ(scene->mMeshes[0]->mNumVertices, 8u);
}
+2 -16
View File
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2025, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -50,18 +48,7 @@ using namespace ::Assimp::Profiling;
class utProfiler : public ::testing::Test {
public:
LogStream *m_stream;
/*virtual void SetUp() {
m_stream = new UTLogStream;
DefaultLogger::create();
DefaultLogger::get()->attachStream( m_stream );
}
virtual void TearDown() {
DefaultLogger::get()->detatchStream( m_stream );
m_stream = nullptr;
}*/
LogStream *mStream = nullptr;
};
TEST_F( utProfiler, addRegion_success ) {
@@ -70,8 +57,7 @@ TEST_F( utProfiler, addRegion_success ) {
for ( int i=0; i<10; i++ ) {
volatile int j=0;
j++;
(void)j; /* avoid gcc-16 warnings about unused variable */
}
myProfiler.EndRegion( "t1" );
//UTLogStream *stream( (UTLogStream*) m_stream );
//EXPECT_FALSE( stream->m_messages.empty() );
}
+1 -1
View File
@@ -50,7 +50,7 @@ class utSceneCombiner : public ::testing::Test {
};
TEST_F(utSceneCombiner, MergeMeshes_ValidNames_Test) {
std::vector<aiMesh *> merge_list;
MeshArray merge_list;
aiMesh *mesh1 = new aiMesh;
mesh1->mName.Set("mesh_1");
merge_list.push_back(mesh1);