Merge branch 'master' into dependabot/github_actions/lukka/run-cmake-10

pull/4803/head
Kim Kulling 2023-09-01 15:57:41 +02:00 committed by GitHub
commit 87ddb3c69f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
826 changed files with 78526 additions and 17007 deletions

View File

@ -1,2 +0,0 @@
service_name: travis-pro
repo_token: GZXuNlublKFy7HAewHAZLk5ZwgipTFAOA

View File

@ -99,7 +99,7 @@ jobs:
- name: Set Windows specific CMake arguments - name: Set Windows specific CMake arguments
if: contains(matrix.name, 'windows') if: contains(matrix.name, 'windows')
id: windows_extra_cmake_args id: windows_extra_cmake_args
run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1" run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1 -DASSIMP_BUILD_ZLIB=1"
- name: Set Hunter specific CMake arguments - name: Set Hunter specific CMake arguments
if: contains(matrix.name, 'hunter') if: contains(matrix.name, 'hunter')

View File

@ -57,3 +57,13 @@ jobs:
- name: test - name: test
run: cd build/bin && ./unit run: cd build/bin && ./unit
shell: bash shell: bash
job3:
name: printf-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: run scan_printf script
run: ./scripts/scan_printf.sh
shell: bash

View File

@ -1,6 +1,6 @@
# Open Asset Import Library (assimp) # Open Asset Import Library (assimp)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Copyright (c) 2006-2022, assimp team # Copyright (c) 2006-2023, assimp team
# #
# All rights reserved. # All rights reserved.
# #
@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd" SHA1 "e6396699e414120e32557fe92db097b7655b760b"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
@ -84,10 +84,6 @@ OPTION( ASSIMP_NO_EXPORT
"Disable Assimp's export functionality." "Disable Assimp's export functionality."
OFF OFF
) )
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
OFF
)
OPTION( ASSIMP_BUILD_ASSIMP_TOOLS OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
"If the supplementary tools for Assimp are built in addition to the library." "If the supplementary tools for Assimp are built in addition to the library."
OFF OFF
@ -134,6 +130,18 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF OFF
) )
IF (WIN32)
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
ON
)
ELSE()
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
ON
)
ENDIF()
IF (WIN32) IF (WIN32)
# Use subset of Windows.h # Use subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
@ -260,6 +268,11 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON) SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF() ENDIF()
IF(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)
MESSAGE(STATUS "GCC13 detected disabling \"-Wdangling-reference\" in Cpp files as it appears to be a false positive")
ADD_COMPILE_OPTIONS("$<$<COMPILE_LANGUAGE:CXX>:-Wno-dangling-reference>")
ENDIF()
# hide all not-exported symbols # hide all not-exported symbols
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" ) IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
@ -273,17 +286,19 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
ELSEIF(MSVC) ELSEIF(MSVC)
# enable multi-core compilation with MSVC # enable multi-core compilation with MSVC
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX ) ADD_COMPILE_OPTIONS(/bigobj)
ELSE() # msvc ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX) ADD_COMPILE_OPTIONS(/MP /bigobj)
ENDIF() ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
ADD_COMPILE_OPTIONS(/wd4244) #supress warning for double to float conversion if Double precission is activated # supress warning for double to float conversion if Double precission is activated
ADD_COMPILE_OPTIONS(/wd4244)
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF") SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
@ -388,14 +403,6 @@ IF (NOT TARGET uninstall AND ASSIMP_INSTALL)
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF() ENDIF()
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
add_definitions(-DDDL_STATIC_LIBRARY=OFF)
endif()
IF( UNIX ) IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
@ -488,7 +495,11 @@ ELSE()
FIND_PACKAGE(ZLIB) FIND_PACKAGE(ZLIB)
ENDIF() ENDIF()
IF( NOT ZLIB_FOUND ) IF ( NOT ZLIB_FOUND AND NOT ASSIMP_BUILD_ZLIB )
message( FATAL_ERROR
"Build configured with -DASSIMP_BUILD_ZLIB=OFF but unable to find zlib"
)
ELSEIF( NOT ZLIB_FOUND )
MESSAGE(STATUS "compiling zlib from sources") MESSAGE(STATUS "compiling zlib from sources")
INCLUDE(CheckIncludeFile) INCLUDE(CheckIncludeFile)
INCLUDE(CheckTypeSize) INCLUDE(CheckTypeSize)

128
CODE_OF_CONDUCT.md 100644
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -1,14 +1,9 @@
FROM ubuntu:14.04 FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y ninja-build \
git cmake build-essential software-properties-common git cmake build-essential software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update && apt-get install -y gcc-4.9 g++-4.9 && \ RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
cd /usr/bin && \
rm gcc g++ cpp && \
ln -s gcc-4.9 gcc && \
ln -s g++-4.9 g++ && \
ln -s cpp-4.9 cpp
WORKDIR /opt WORKDIR /opt
@ -19,7 +14,8 @@ WORKDIR /opt/assimp
RUN git checkout master \ RUN git checkout master \
&& mkdir build && cd build && \ && mkdir build && cd build && \
cmake \ cmake -G 'Ninja' \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DASSIMP_BUILD_ASSIMP_TOOLS=ON \
.. && \ .. && \
make && make install ninja -j4 && ninja install

View File

@ -1,6 +1,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
================================== ==================================
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
### Current project status ### ### Current project status ###
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg) ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
@ -14,7 +16,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
[![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open") [![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
<br> <br>
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
@ -23,15 +24,19 @@ Additionally, assimp features various __mesh post processing tools__: normals an
### Latest Doc's ### ### Latest Doc's ###
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
### Get involved ### ### Prebuild binaries ###
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib)
<br>
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
<br>
Please check our Wiki as well: https://github.com/assimp/assimp/wiki
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
### Communities ###
- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions)
- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/)
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
#### Supported file formats #### #### Supported file formats ####
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md)
@ -66,25 +71,18 @@ Open Asset Import Library is implemented in C++. The directory structure looks l
/port Ports to other languages and scripts to maintain those. /port Ports to other languages and scripts to maintain those.
/test Unit- and regression tests, test suite of models /test Unit- and regression tests, test suite of models
/tools Tools (old assimp viewer, command line `assimp`) /tools Tools (old assimp viewer, command line `assimp`)
/samples A small number of samples to illustrate possible /samples A small number of samples to illustrate possible use-cases for Assimp
use cases for Assimp
The source code is organized in the following way: The source code is organized in the following way:
code/Common The base implementation for importers and the infrastructure code/Common The base implementation for importers and the infrastructure
code/CApi Special implementations which are only used for the C-API
code/Geometry A collection of geometry tools
code/Material The material system
code/PBR An exporter for physical based models
code/PostProcessing The post-processing steps code/PostProcessing The post-processing steps
code/AssetLib/<FormatName> Implementation for import and export for the format code/AssetLib/<FormatName> Implementation for import and export for the format
### Where to get help ###
For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
(CHMs for Windows are included in some release packages and should be located right here in the root folder).
If the docs don't solve your problem, ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
### Contributing ### ### Contributing ###
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
a pull request with your changes against the main repository's `master` branch. a pull request with your changes against the main repository's `master` branch.

View File

@ -322,7 +322,6 @@ struct Texture {
//! Default constructor //! Default constructor
Texture() AI_NO_EXCEPT Texture() AI_NO_EXCEPT
: mTextureBlend(0.0f), : mTextureBlend(0.0f),
mMapName(),
mOffsetU(0.0), mOffsetU(0.0),
mOffsetV(0.0), mOffsetV(0.0),
mScaleU(1.0), mScaleU(1.0),
@ -334,51 +333,11 @@ struct Texture {
mTextureBlend = get_qnan(); mTextureBlend = get_qnan();
} }
Texture(const Texture &other) : Texture(const Texture &other) = default;
mTextureBlend(other.mTextureBlend),
mMapName(other.mMapName),
mOffsetU(other.mOffsetU),
mOffsetV(other.mOffsetV),
mScaleU(other.mScaleU),
mScaleV(other.mScaleV),
mRotation(other.mRotation),
mMapMode(other.mMapMode),
bPrivate(other.bPrivate),
iUVSrc(other.iUVSrc) {
// empty
}
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(other.mTextureBlend), Texture(Texture &&other) AI_NO_EXCEPT = default;
mMapName(std::move(other.mMapName)),
mOffsetU(other.mOffsetU),
mOffsetV(other.mOffsetV),
mScaleU(other.mScaleU),
mScaleV(other.mScaleV),
mRotation(other.mRotation),
mMapMode(other.mMapMode),
bPrivate(other.bPrivate),
iUVSrc(other.iUVSrc) {
// empty
}
Texture &operator=(Texture &&other) AI_NO_EXCEPT { Texture &operator=(Texture &&other) AI_NO_EXCEPT = default;
if (this == &other) {
return *this;
}
mTextureBlend = other.mTextureBlend;
mMapName = std::move(other.mMapName);
mOffsetU = other.mOffsetU;
mOffsetV = other.mOffsetV;
mScaleU = other.mScaleU;
mScaleV = other.mScaleV;
mRotation = other.mRotation;
mMapMode = other.mMapMode;
bPrivate = other.bPrivate;
iUVSrc = other.iUVSrc;
return *this;
}
//! Specifies the blend factor for the texture //! Specifies the blend factor for the texture
ai_real mTextureBlend; ai_real mTextureBlend;
@ -436,83 +395,9 @@ struct Material {
// empty // empty
} }
Material(const Material &other) : Material(const Material &other) = default;
mName(other.mName),
mDiffuse(other.mDiffuse),
mSpecularExponent(other.mSpecularExponent),
mShininessStrength(other.mShininessStrength),
mSpecular(other.mSpecular),
mAmbient(other.mAmbient),
mShading(other.mShading),
mTransparency(other.mTransparency),
sTexDiffuse(other.sTexDiffuse),
sTexOpacity(other.sTexOpacity),
sTexSpecular(other.sTexSpecular),
sTexReflective(other.sTexReflective),
sTexBump(other.sTexBump),
sTexEmissive(other.sTexEmissive),
sTexShininess(other.sTexShininess),
mBumpHeight(other.mBumpHeight),
mEmissive(other.mEmissive),
sTexAmbient(other.sTexAmbient),
mTwoSided(other.mTwoSided) {
// empty
}
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it virtual ~Material() = default;
Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)),
mDiffuse(other.mDiffuse),
mSpecularExponent(other.mSpecularExponent),
mShininessStrength(other.mShininessStrength),
mSpecular(other.mSpecular),
mAmbient(other.mAmbient),
mShading(other.mShading),
mTransparency(other.mTransparency),
sTexDiffuse(std::move(other.sTexDiffuse)),
sTexOpacity(std::move(other.sTexOpacity)),
sTexSpecular(std::move(other.sTexSpecular)),
sTexReflective(std::move(other.sTexReflective)),
sTexBump(std::move(other.sTexBump)),
sTexEmissive(std::move(other.sTexEmissive)),
sTexShininess(std::move(other.sTexShininess)),
mBumpHeight(other.mBumpHeight),
mEmissive(other.mEmissive),
sTexAmbient(std::move(other.sTexAmbient)),
mTwoSided(other.mTwoSided) {
// empty
}
Material &operator=(Material &&other) AI_NO_EXCEPT {
if (this == &other) {
return *this;
}
mName = std::move(other.mName);
mDiffuse = other.mDiffuse;
mSpecularExponent = other.mSpecularExponent;
mShininessStrength = other.mShininessStrength,
mSpecular = other.mSpecular;
mAmbient = other.mAmbient;
mShading = other.mShading;
mTransparency = other.mTransparency;
sTexDiffuse = std::move(other.sTexDiffuse);
sTexOpacity = std::move(other.sTexOpacity);
sTexSpecular = std::move(other.sTexSpecular);
sTexReflective = std::move(other.sTexReflective);
sTexBump = std::move(other.sTexBump);
sTexEmissive = std::move(other.sTexEmissive);
sTexShininess = std::move(other.sTexShininess);
mBumpHeight = other.mBumpHeight;
mEmissive = other.mEmissive;
sTexAmbient = std::move(other.sTexAmbient);
mTwoSided = other.mTwoSided;
return *this;
}
virtual ~Material() {
// empty
}
//! Name of the material //! Name of the material
std::string mName; std::string mName;

View File

@ -266,8 +266,15 @@ void Discreet3DSImporter::ParseMainChunk() {
}; };
ASSIMP_3DS_END_CHUNK(); ASSIMP_3DS_END_CHUNK();
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code-return"
#endif
// recursively continue processing this hierarchy level // recursively continue processing this hierarchy level
return ParseMainChunk(); return ParseMainChunk();
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -68,7 +68,7 @@ using namespace D3DS;
class Discreet3DSImporter : public BaseImporter { class Discreet3DSImporter : public BaseImporter {
public: public:
Discreet3DSImporter(); Discreet3DSImporter();
~Discreet3DSImporter(); ~Discreet3DSImporter() override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

@ -69,9 +69,7 @@ public:
// empty // empty
} }
virtual ~Resource() { virtual ~Resource() = default;
// empty
}
virtual ResourceType getType() const { virtual ResourceType getType() const {
return ResourceType::RT_Unknown; return ResourceType::RT_Unknown;
@ -95,7 +93,7 @@ public:
// empty // empty
} }
~EmbeddedTexture() = default; ~EmbeddedTexture() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_EmbeddedTexture2D; return ResourceType::RT_EmbeddedTexture2D;
@ -112,7 +110,7 @@ public:
// empty // empty
} }
~Texture2DGroup() = default; ~Texture2DGroup() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_Texture2DGroup; return ResourceType::RT_Texture2DGroup;
@ -129,7 +127,7 @@ public:
// empty // empty
} }
~BaseMaterials() = default; ~BaseMaterials() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_BaseMaterials; return ResourceType::RT_BaseMaterials;
@ -154,7 +152,7 @@ public:
// empty // empty
} }
~Object() = default; ~Object() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_Object; return ResourceType::RT_Object;

View File

@ -83,7 +83,7 @@ void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScen
namespace D3MF { namespace D3MF {
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) : D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() { mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene) {
// empty // empty
} }

View File

@ -227,7 +227,9 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
} }
} else if (TokenMatch(buffer, "texture", 7)) { } else if (TokenMatch(buffer, "texture", 7)) {
SkipSpaces(&buffer); SkipSpaces(&buffer);
buffer = AcGetString(buffer, obj.texture); std::string texture;
buffer = AcGetString(buffer, texture);
obj.textures.push_back(texture);
} else if (TokenMatch(buffer, "texrep", 6)) { } else if (TokenMatch(buffer, "texrep", 6)) {
SkipSpaces(&buffer); SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
@ -351,8 +353,8 @@ void AC3DImporter::ConvertMaterial(const Object &object,
s.Set(matSrc.name); s.Set(matSrc.name);
matDest.AddProperty(&s, AI_MATKEY_NAME); matDest.AddProperty(&s, AI_MATKEY_NAME);
} }
if (object.texture.length()) { if (!object.textures.empty()) {
s.Set(object.texture); s.Set(object.textures[0]);
matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
// UV transformation // UV transformation
@ -532,7 +534,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// allocate UV coordinates, but only if the texture name for the // allocate UV coordinates, but only if the texture name for the
// surface is not empty // surface is not empty
aiVector3D *uv = nullptr; aiVector3D *uv = nullptr;
if (object.texture.length()) { if (!object.textures.empty()) {
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2; mesh->mNumUVComponents[0] = 2;
} }

View File

@ -125,7 +125,6 @@ public:
type(World), type(World),
name(), name(),
children(), children(),
texture(),
texRepeat(1.f, 1.f), texRepeat(1.f, 1.f),
texOffset(0.0f, 0.0f), texOffset(0.0f, 0.0f),
rotation(), rotation(),
@ -151,7 +150,8 @@ public:
std::vector<Object> children; std::vector<Object> children;
// texture to be assigned to all surfaces of the object // texture to be assigned to all surfaces of the object
std::string texture; // the .acc format supports up to 4 textures
std::vector<std::string> textures;
// texture repat factors (scaling for all coordinates) // texture repat factors (scaling for all coordinates)
aiVector2D texRepeat, texOffset; aiVector2D texRepeat, texOffset;

View File

@ -83,11 +83,7 @@ void AMFImporter::Clear() {
AMFImporter::AMFImporter() AI_NO_EXCEPT : AMFImporter::AMFImporter() AI_NO_EXCEPT :
mNodeElement_Cur(nullptr), mNodeElement_Cur(nullptr),
mXmlParser(nullptr), mXmlParser(nullptr) {
mUnit(),
mVersion(),
mMaterial_Converted(),
mTexture_Converted() {
// empty // empty
} }

View File

@ -282,11 +282,11 @@ public:
bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const; bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const; bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const; bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
void Throw_CloseNotFound(const std::string &nodeName); AI_WONT_RETURN void Throw_CloseNotFound(const std::string &nodeName) AI_WONT_RETURN_SUFFIX;
void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName); AI_WONT_RETURN void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName); AI_WONT_RETURN void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription); AI_WONT_RETURN void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) AI_WONT_RETURN_SUFFIX;
void Throw_ID_NotFound(const std::string &pID) const; AI_WONT_RETURN void Throw_ID_NotFound(const std::string &pID) const AI_WONT_RETURN_SUFFIX;
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node); void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
bool XML_SearchNode(const std::string &nodeName); bool XML_SearchNode(const std::string &nodeName);
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString); void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);

View File

@ -88,9 +88,7 @@ public:
std::list<AMFNodeElementBase *> Child; ///< Child elements. std::list<AMFNodeElementBase *> Child; ///< Child elements.
public: /// Destructor, virtual.. public: /// Destructor, virtual..
virtual ~AMFNodeElementBase() { virtual ~AMFNodeElementBase() = default;
// empty
}
/// Disabled copy constructor and co. /// Disabled copy constructor and co.
AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete; AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete;
@ -103,7 +101,7 @@ protected:
/// \param [in] pType - element type. /// \param [in] pType - element type.
/// \param [in] pParent - parent element. /// \param [in] pParent - parent element.
AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) : AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
Type(pType), ID(), Parent(pParent), Child() { Type(pType), Parent(pParent) {
// empty // empty
} }
}; // class IAMFImporter_NodeElement }; // class IAMFImporter_NodeElement
@ -174,7 +172,7 @@ struct AMFColor : public AMFNodeElementBase {
/// @brief Constructor. /// @brief Constructor.
/// @param [in] pParent - pointer to parent node. /// @param [in] pParent - pointer to parent node.
AMFColor(AMFNodeElementBase *pParent) : AMFColor(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() { AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color() {
// empty // empty
} }
}; };
@ -270,7 +268,7 @@ struct AMFTexMap : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFTexMap(AMFNodeElementBase *pParent) : AMFTexMap(AMFNodeElementBase *pParent) :
AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() { AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{} {
// empty // empty
} }
}; };

View File

@ -815,6 +815,7 @@ nl_clean_loop:
for (; next_it != nodeArray.end(); ++next_it) { for (; next_it != nodeArray.end(); ++next_it) {
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) { if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop. // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
// FIXME: this leaks memory on test models test8.amf and test9.amf
nodeArray.erase(nl_it); nodeArray.erase(nl_it);
goto nl_clean_loop; goto nl_clean_loop;

View File

@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers // internal headers
@ -322,21 +321,6 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nd->mNodeName.Set(me->mName + ".Target"); nd->mNodeName.Set(me->mName + ".Target");
// If there is no input position channel we will need
// to supply the default position from the node's
// local transformation matrix.
/*TargetAnimationHelper helper;
if (me->mAnim.akeyPositions.empty())
{
aiMatrix4x4& mat = (*i)->mTransform;
helper.SetFixedMainAnimationChannel(aiVector3D(
mat.a4, mat.b4, mat.c4));
}
else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
helper.Process(&me->mTargetAnim.akeyPositions);*/
// Allocate the key array and fill it // Allocate the key array and fill it
nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size(); nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];

View File

@ -304,7 +304,6 @@ void Parser::Parse() {
} }
AI_ASE_HANDLE_TOP_LEVEL_SECTION(); AI_ASE_HANDLE_TOP_LEVEL_SECTION();
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -480,6 +479,11 @@ void Parser::ParseLV1MaterialListBlock() {
if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) { if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) {
ParseLV4MeshLong(iMaterialCount); ParseLV4MeshLong(iMaterialCount);
if (UINT_MAX - iOldMaterialCount < iMaterialCount) {
LogWarning("Out of range: material index is too large");
return;
}
// now allocate enough storage to hold all materials // now allocate enough storage to hold all materials
m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID")); m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
continue; continue;
@ -734,7 +738,6 @@ void Parser::ParseLV3MapBlock(Texture &map) {
} }
AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX"); AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -859,7 +862,6 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) {
} }
AI_ASE_HANDLE_TOP_LEVEL_SECTION(); AI_ASE_HANDLE_TOP_LEVEL_SECTION();
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -883,7 +885,6 @@ void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) {
} }
AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS"); AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1189,7 +1190,6 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) {
} }
AI_ASE_HANDLE_SECTION("2", "*NODE_TM"); AI_ASE_HANDLE_SECTION("2", "*NODE_TM");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) { void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
@ -1310,7 +1310,6 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
} }
AI_ASE_HANDLE_SECTION("2", "*MESH"); AI_ASE_HANDLE_SECTION("2", "*MESH");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) { void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
@ -1344,7 +1343,6 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS"); AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) { void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
@ -1414,7 +1412,6 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
} }
AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX"); AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshVertexListBlock( void Parser::ParseLV3MeshVertexListBlock(
@ -1443,7 +1440,6 @@ void Parser::ParseLV3MeshVertexListBlock(
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) { void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
@ -1470,7 +1466,6 @@ void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh)
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices, void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
@ -1503,7 +1498,6 @@ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
@ -1532,7 +1526,6 @@ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) { void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
@ -1567,7 +1560,6 @@ void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL"); AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) { void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) {
@ -1595,7 +1587,6 @@ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh)
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) { void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
@ -1623,7 +1614,6 @@ void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh)
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST"); AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) { void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
@ -1681,7 +1671,6 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
} }
AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS"); AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFace(ASE::Face &out) { void Parser::ParseLV4MeshFace(ASE::Face &out) {

View File

@ -7,7 +7,7 @@ For details, see http://sourceforge.net/projects/libb64
#include "cencode.h" // changed from <B64/cencode.h> #include "cencode.h" // changed from <B64/cencode.h>
const int CHARS_PER_LINE = 72; static const int CHARS_PER_LINE = 72;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)

View File

@ -150,7 +150,7 @@ AI_WONT_RETURN void B3DImporter::Fail(const string &str) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte() { int B3DImporter::ReadByte() {
if (_pos > _buf.size()) { if (_pos >= _buf.size()) {
Fail("EOF"); Fail("EOF");
} }
@ -418,7 +418,6 @@ void B3DImporter::ReadTRIS(int v0) {
ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2); ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
#endif #endif
Fail("Bad triangle index"); Fail("Bad triangle index");
continue;
} }
face->mNumIndices = 3; face->mNumIndices = 3;
face->mIndices = new unsigned[3]; face->mIndices = new unsigned[3];

View File

@ -52,8 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
template <> template <>
const char *LogFunctions<BlenderBMeshConverter>::Prefix() { const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
static auto prefix = "BLEND_BMESH: "; return "BLEND_BMESH: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp

View File

@ -96,7 +96,8 @@ struct CustomDataTypeDescription {
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures * other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
* use a special readfunction for that cases * use a special readfunction for that cases
*/ */
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert), static std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { {
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge), DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),

View File

@ -106,9 +106,7 @@ struct ElemBase {
// empty // empty
} }
virtual ~ElemBase() { virtual ~ElemBase() = default;
// empty
}
/** Type name of the element. The type /** Type name of the element. The type
* string points is the `c_str` of the `name` attribute of the * string points is the `c_str` of the `name` attribute of the

View File

@ -80,8 +80,7 @@ namespace Assimp {
template <> template <>
const char *LogFunctions<BlenderImporter>::Prefix() { const char *LogFunctions<BlenderImporter>::Prefix() {
static auto prefix = "BLEND: "; return "BLEND: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp
@ -116,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
delete modifier_cache; delete modifier_cache;
} }
static const char * const Tokens[] = { "BLENDER" }; static const char Token[] = "BLENDER";
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// note: this won't catch compressed files return ParseMagicToken(pFile, pIOHandler).error.empty();
static const char *tokens[] = { "<BLENDER", "blender" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -143,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void BlenderImporter::InternReadFile(const std::string &pFile, void BlenderImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) { aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
std::vector<char> uncompressed;
#endif
FileDatabase file; FileDatabase file;
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb")); StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
if (!stream) { if (!streamOrError.error.empty()) {
ThrowException("Could not open file for reading"); ThrowException(streamOrError.error);
} }
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
char magic[8] = { 0 }; char version[4] = { 0 };
stream->Read(magic, 7, 1); file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
if (strcmp(magic, Tokens[0])) { file.little = (stream->Read(version, 1, 1), version[0] == 'v');
// Check for presence of the gzip header. If yes, assume it is a
// compressed blend file and try uncompressing it, else fail. This is to
// avoid uncompressing random files which our loader might end up with.
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
#else
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
}
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file"); stream->Read(version, 3, 1);
if (magic[2] != 8) { version[3] = '\0';
ThrowException("Unsupported GZIP compression method");
}
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer LogInfo("Blender version is ", version[0], ".", version + 1,
stream->Seek(0L, aiOrigin_SET);
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
size_t total = 0;
Compression compression;
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
compression.close();
}
// replace the input stream with a memory stream
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed.data()), total);
// .. and retry
stream->Read(magic, 7, 1);
if (strcmp(magic, "BLENDER")) {
ThrowException("Found no BLENDER magic word in decompressed GZIP file");
}
#endif
}
file.i64bit = (stream->Read(magic, 1, 1), magic[0] == '-');
file.little = (stream->Read(magic, 1, 1), magic[0] == 'v');
stream->Read(magic, 3, 1);
magic[3] = '\0';
LogInfo("Blender version is ", magic[0], ".", magic + 1,
" (64bit: ", file.i64bit ? "true" : "false", " (64bit: ", file.i64bit ? "true" : "false",
", little endian: ", file.little ? "true" : "false", ")"); ", little endian: ", file.little ? "true" : "false", ")");
@ -1339,4 +1293,55 @@ aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, Convers
return node.release(); return node.release();
} }
BlenderImporter::StreamOrError BlenderImporter::ParseMagicToken(const std::string &pFile, IOSystem *pIOHandler) const {
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (stream == nullptr) {
return {{}, {}, "Could not open file for reading"};
}
char magic[8] = { 0 };
stream->Read(magic, 7, 1);
if (strcmp(magic, Token) == 0) {
return {stream, {}, {}};
}
// Check for presence of the gzip header. If yes, assume it is a
// compressed blend file and try uncompressing it, else fail. This is to
// avoid uncompressing random files which our loader might end up with.
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
return {{}, {}, "BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"};
#else
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
return {{}, {}, "BLENDER magic bytes are missing, couldn't find GZIP header either"};
}
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
if (magic[2] != 8) {
return {{}, {}, "Unsupported GZIP compression method"};
}
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
stream->Seek(0L, aiOrigin_SET);
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
size_t total = 0;
Compression compression;
auto uncompressed = std::make_shared<std::vector<char>>();
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), *uncompressed);
compression.close();
}
// replace the input stream with a memory stream
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed->data()), total);
// .. and retry
stream->Read(magic, 7, 1);
if (strcmp(magic, Token) == 0) {
return {stream, uncompressed, {}};
}
return {{}, {}, "Found no BLENDER magic word in decompressed GZIP file"};
#endif
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -180,6 +180,19 @@ private:
const Blender::MTex *tex, const Blender::MTex *tex,
Blender::ConversionData &conv_data); Blender::ConversionData &conv_data);
// TODO: Move to a std::variant, once c++17 is supported.
struct StreamOrError {
std::shared_ptr<IOStream> stream;
std::shared_ptr<std::vector<char>> input;
std::string error;
};
// Returns either a stream (and optional input data for the stream) or
// an error if it can't parse the magic token.
StreamOrError ParseMagicToken(
const std::string &pFile,
IOSystem *pIOHandler) const;
private: // static stuff, mostly logging and error reporting. private: // static stuff, mostly logging and error reporting.
// -------------------- // --------------------
static void CheckActualType(const Blender::ElemBase *dt, static void CheckActualType(const Blender::ElemBase *dt,

View File

@ -62,9 +62,7 @@ public:
/** /**
* The class destructor, virtual. * The class destructor, virtual.
*/ */
virtual ~BlenderModifier() { virtual ~BlenderModifier() = default;
// empty
}
// -------------------- // --------------------
/** /**

View File

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

View File

@ -182,7 +182,7 @@ struct MVert : ElemBase {
int bweight; int bweight;
MVert() : MVert() :
ElemBase(), flag(0), mat_nr(0), bweight(0) {} flag(0), mat_nr(0), bweight(0) {}
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -417,7 +417,6 @@ struct CustomDataLayer : ElemBase {
std::shared_ptr<ElemBase> data; // must be converted to real type according type member std::shared_ptr<ElemBase> data; // must be converted to real type according type member
CustomDataLayer() : CustomDataLayer() :
ElemBase(),
type(0), type(0),
offset(0), offset(0),
flag(0), flag(0),
@ -729,7 +728,7 @@ struct Object : ElemBase {
ListBase modifiers; ListBase modifiers;
Object() : Object() :
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() { type(Type_EMPTY), parent(nullptr) {
// empty // empty
} }
}; };
@ -741,8 +740,7 @@ struct Base : ElemBase {
std::shared_ptr<Object> object WARN; std::shared_ptr<Object> object WARN;
Base() : Base() :
ElemBase(), prev(nullptr), next(), object() { prev(nullptr) {
// empty
// empty // empty
} }
}; };
@ -758,10 +756,7 @@ struct Scene : ElemBase {
ListBase base; ListBase base;
Scene() : Scene() = default;
ElemBase(), camera(), world(), basact(), master_collection() {
// empty
}
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -791,10 +786,7 @@ struct Image : ElemBase {
short gen_x, gen_y, gen_type; short gen_x, gen_y, gen_type;
Image() : Image() = default;
ElemBase() {
// empty
}
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -884,7 +876,7 @@ struct Tex : ElemBase {
//char use_nodes; //char use_nodes;
Tex() : Tex() :
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() { imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS) {
// empty // empty
} }
}; };
@ -976,10 +968,7 @@ struct MTex : ElemBase {
//float shadowfac; //float shadowfac;
//float zenupfac, zendownfac, blendfac; //float zenupfac, zendownfac, blendfac;
MTex() : MTex() = default;
ElemBase() {
// empty
}
}; };
} // namespace Blender } // namespace Blender

View File

@ -62,8 +62,7 @@ namspace Assimp
{ {
template< > const char* LogFunctions< BlenderTessellatorGL >::Prefix() template< > const char* LogFunctions< BlenderTessellatorGL >::Prefix()
{ {
static auto prefix = "BLEND_TESS_GL: "; return "BLEND_TESS_GL: ";
return prefix;
} }
} }
@ -81,9 +80,7 @@ BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
BlenderTessellatorGL::~BlenderTessellatorGL( ) BlenderTessellatorGL::~BlenderTessellatorGL() = default;
{
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices ) void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
@ -259,8 +256,7 @@ namespace Assimp
{ {
template< > const char* LogFunctions< BlenderTessellatorP2T >::Prefix() template< > const char* LogFunctions< BlenderTessellatorP2T >::Prefix()
{ {
static auto prefix = "BLEND_TESS_P2T: "; return "BLEND_TESS_P2T: ";
return prefix;
} }
} }

View File

@ -86,8 +86,7 @@ void GetWriterInfo(int &id, String &appname) {
namespace Assimp { namespace Assimp {
template<> const char* LogFunctions<C4DImporter>::Prefix() { template<> const char* LogFunctions<C4DImporter>::Prefix() {
static auto prefix = "C4D: "; return "C4D: ";
return prefix;
} }
} }
@ -106,15 +105,10 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
C4DImporter::C4DImporter() C4DImporter::C4DImporter() = default;
: BaseImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
C4DImporter::~C4DImporter() { C4DImporter::~C4DImporter() = default;
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const { bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {

View File

@ -448,7 +448,7 @@ void ColladaExporter::WriteLight(size_t pIndex) {
PushTag(); PushTag();
switch (light->mType) { switch (light->mType) {
case aiLightSource_AMBIENT: case aiLightSource_AMBIENT:
WriteAmbienttLight(light); WriteAmbientLight(light);
break; break;
case aiLightSource_DIRECTIONAL: case aiLightSource_DIRECTIONAL:
WriteDirectionalLight(light); WriteDirectionalLight(light);
@ -543,7 +543,7 @@ void ColladaExporter::WriteSpotLight(const aiLight *const light) {
mOutput << startstr << "</spot>" << endstr; mOutput << startstr << "</spot>" << endstr;
} }
void ColladaExporter::WriteAmbienttLight(const aiLight *const light) { void ColladaExporter::WriteAmbientLight(const aiLight *const light) {
const aiColor3D &color = light->mColorAmbient; const aiColor3D &color = light->mColorAmbient;
mOutput << startstr << "<ambient>" << endstr; mOutput << startstr << "<ambient>" << endstr;

View File

@ -101,7 +101,7 @@ protected:
void WritePointLight(const aiLight *const light); void WritePointLight(const aiLight *const light);
void WriteDirectionalLight(const aiLight *const light); void WriteDirectionalLight(const aiLight *const light);
void WriteSpotLight(const aiLight *const light); void WriteSpotLight(const aiLight *const light);
void WriteAmbienttLight(const aiLight *const light); void WriteAmbientLight(const aiLight *const light);
/// Writes the controller library /// Writes the controller library
void WriteControllerLibrary(); void WriteControllerLibrary();

View File

@ -666,7 +666,7 @@ struct ChannelEntry {
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data *mTimeData; ///> Source data array for the time values const Collada::Data *mTimeData; ///> Source data array for the time values
const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data *mValueData; ///> Source datat array for the key value values const Collada::Data *mValueData; ///> Source data array for the key value values
ChannelEntry() : ChannelEntry() :
mChannel(), mChannel(),

View File

@ -92,18 +92,10 @@ inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ColladaLoader::ColladaLoader() : ColladaLoader::ColladaLoader() :
mFileName(),
mMeshIndexByID(),
mMaterialIndexByName(),
mMeshes(),
newMats(),
mCameras(),
mLights(),
mTextures(),
mAnims(),
noSkeletonMesh(false), noSkeletonMesh(false),
removeEmptyBones(false), removeEmptyBones(false),
ignoreUpDirection(false), ignoreUpDirection(false),
ignoreUnitSize(false),
useColladaName(false), useColladaName(false),
mNodeNameCounter(0) { mNodeNameCounter(0) {
// empty // empty
@ -131,6 +123,7 @@ void ColladaLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0; removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
ignoreUnitSize = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UNIT_SIZE, 0) != 0;
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0; useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
} }
@ -179,12 +172,15 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// ... then fill the materials with the now adjusted settings // ... then fill the materials with the now adjusted settings
FillMaterials(parser, pScene); FillMaterials(parser, pScene);
if (!ignoreUnitSize) {
// Apply unit-size scale calculation // Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0,
0, 0, 0, 1); 0, 0, 0, 1);
}
if (!ignoreUpDirection) { if (!ignoreUpDirection) {
// Convert to Y_UP, if different orientation // Convert to Y_UP, if different orientation
if (parser.mUpDirection == ColladaParser::UP_X) { if (parser.mUpDirection == ColladaParser::UP_X) {

View File

@ -239,6 +239,7 @@ protected:
bool noSkeletonMesh; bool noSkeletonMesh;
bool removeEmptyBones; bool removeEmptyBones;
bool ignoreUpDirection; bool ignoreUpDirection;
bool ignoreUnitSize;
bool useColladaName; bool useColladaName;
/** Used by FindNameForNode() to generate unique node names */ /** Used by FindNameForNode() to generate unique node names */

View File

@ -762,6 +762,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
if (text == nullptr) { if (text == nullptr) {
throw DeadlyImportError("Out of data while reading <vertex_weights>"); throw DeadlyImportError("Out of data while reading <vertex_weights>");
} }
SkipSpacesAndLineEnd(&text);
it->first = strtoul10(text, &text); it->first = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text); SkipSpacesAndLineEnd(&text);
if (*text == 0) { if (*text == 0) {
@ -1854,7 +1855,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
default: default:
// LineStrip is not supported due to expected index unmangling // LineStrip is not supported due to expected index unmangling
throw DeadlyImportError("Unsupported primitive type."); throw DeadlyImportError("Unsupported primitive type.");
break;
} }
// store the face size to later reconstruct the face from // store the face size to later reconstruct the face from

View File

@ -65,7 +65,6 @@ public:
LineReader(StreamReaderLE& reader) LineReader(StreamReaderLE& reader)
: splitter(reader,false,true) : splitter(reader,false,true)
, groupcode( 0 ) , groupcode( 0 )
, value()
, end() { , end() {
// empty // empty
} }
@ -186,8 +185,7 @@ struct InsertBlock {
InsertBlock() InsertBlock()
: pos() : pos()
, scale(1.f,1.f,1.f) , scale(1.f,1.f,1.f)
, angle() , angle() {
, name() {
// empty // empty
} }

View File

@ -71,7 +71,7 @@ static const aiColor4D AI_DXF_DEFAULT_COLOR(aiColor4D(0.6f, 0.6f, 0.6f, 0.6f));
// color indices for DXF - 16 are supported, the table is // color indices for DXF - 16 are supported, the table is
// taken directly from the DXF spec. // taken directly from the DXF spec.
static aiColor4D g_aclrDxfIndexColors[] = { static aiColor4D g_aclrDxfIndexColors[] = {
aiColor4D (0.6f, 0.6f, 0.6f, 1.0f), aiColor4D(0.6f, 0.6f, 0.6f, 1.0f),
aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red
aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green
aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue
@ -88,6 +88,7 @@ static aiColor4D g_aclrDxfIndexColors[] = {
aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white
aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet
}; };
#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0])) #define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
#define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC" #define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC"
@ -109,14 +110,6 @@ static const aiImporterDesc desc = {
"dxf" "dxf"
}; };
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
DXFImporter::DXFImporter() = default;
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
DXFImporter::~DXFImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const { bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
@ -229,7 +222,7 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
ASSIMP_LOG_VERBOSE_DEBUG("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount); ASSIMP_LOG_VERBOSE_DEBUG("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
} }
if (! output.blocks.size() ) { if (output.blocks.empty()) {
throw DeadlyImportError("DXF: no data blocks loaded"); throw DeadlyImportError("DXF: no data blocks loaded");
} }
@ -587,10 +580,11 @@ void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output)
} }
} }
#define DXF_POLYLINE_FLAG_CLOSED 0x1 static constexpr unsigned int DXF_POLYLINE_FLAG_CLOSED = 0x1;
#define DXF_POLYLINE_FLAG_3D_POLYLINE 0x8 // Currently unused
#define DXF_POLYLINE_FLAG_3D_POLYMESH 0x10 //static constexpr unsigned int DXF_POLYLINE_FLAG_3D_POLYLINE = 0x8;
#define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40 //static constexpr unsigned int DXF_POLYLINE_FLAG_3D_POLYMESH = 0x10;
static constexpr unsigned int DXF_POLYLINE_FLAG_POLYFACEMESH = 0x40;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) { void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) {
@ -639,12 +633,6 @@ void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output)
reader++; reader++;
} }
//if (!(line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH)) {
// DefaultLogger::get()->warn((Formatter::format("DXF: polyline not currently supported: "),line.flags));
// output.blocks.back().lines.pop_back();
// return;
//}
if (vguess && line.positions.size() != vguess) { if (vguess && line.positions.size() != vguess) {
ASSIMP_LOG_WARN("DXF: unexpected vertex count in polymesh: ", ASSIMP_LOG_WARN("DXF: unexpected vertex count in polymesh: ",
line.positions.size(),", expected ", vguess ); line.positions.size(),", expected ", vguess );
@ -734,12 +722,18 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
case 71: case 71:
case 72: case 72:
case 73: case 73:
case 74: case 74: {
if (cnti == 4) { if (cnti == 4) {
ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring"); ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
break; break;
} }
indices[cnti++] = reader.ValueAsUnsignedInt(); const int index = reader.ValueAsSignedInt();
if (index >= 0) {
indices[cnti++] = static_cast<unsigned int>(index);
} else {
indices[cnti++] = static_cast<unsigned int>(-index);
}
}
break; break;
// color // color
@ -777,8 +771,7 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output) {
{
// (note) this is also used for for parsing line entities, so we // (note) this is also used for for parsing line entities, so we
// must handle the vertex_count == 2 case as well. // must handle the vertex_count == 2 case as well.
@ -795,8 +788,7 @@ void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output)
if (reader.GroupCode() == 0) { if (reader.GroupCode() == 0) {
break; break;
} }
switch (reader.GroupCode()) switch (reader.GroupCode()) {
{
// 8 specifies the layer // 8 specifies the layer
case 8: case 8:

View File

@ -68,8 +68,8 @@ namespace DXF {
*/ */
class DXFImporter : public BaseImporter { class DXFImporter : public BaseImporter {
public: public:
DXFImporter(); DXFImporter() = default;
~DXFImporter() override; ~DXFImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

@ -139,6 +139,7 @@ size_t Offset(const char* begin, const char* cursor) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void TokenizeError(const std::string& message, const char* begin, const char* cursor) AI_WONT_RETURN_SUFFIX;
void TokenizeError(const std::string& message, const char* begin, const char* cursor) { void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
TokenizeError(message, Offset(begin, cursor)); TokenizeError(message, Offset(begin, cursor));
} }
@ -341,8 +342,7 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits) bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
{
// the first word contains the offset at which this block ends // the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@ -408,7 +408,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// XXX this is vulnerable to stack overflowing .. // XXX this is vulnerable to stack overflowing ..
while(Offset(input, cursor) < end_offset - sentinel_block_length) { while(Offset(input, cursor) < end_offset - sentinel_block_length) {
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
} }
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
@ -431,8 +431,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
{
ai_assert(input); ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file"); ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
@ -465,7 +464,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
try try
{ {
while (cursor < end ) { while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
break; break;
} }
} }

View File

@ -55,6 +55,7 @@ const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 nul
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
static std::string NULL_RECORD_STRING(NumNullRecords, '\0');
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit const int64_t SECOND = 46186158000; // FBX's kTime unit

View File

@ -93,6 +93,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
mSceneOut(out), mSceneOut(out),
doc(doc), doc(doc),
mRemoveEmptyBones(removeEmptyBones) { mRemoveEmptyBones(removeEmptyBones) {
// animations need to be converted first since this will // animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed // populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated. // to determine which nodes need to be generated.
@ -421,16 +423,32 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
// NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
// All transformations to the camera will be handled by its node in the scenegraph.
out_camera->mPosition = aiVector3D(0.0f); out_camera->mPosition = aiVector3D(0.0f);
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); // NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
// mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
out_camera->mClipPlaneNear = cam.NearPlane(); // TODO: This is not a complete solution for how FBX cameras can be stored.
out_camera->mClipPlaneFar = cam.FarPlane(); // TODO: Incorporate non-square pixel aspect ratio.
// TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
float fov_deg = cam.FieldOfView();
// If FOV not specified in file, compute using FilmWidth and FocalLength.
if (fov_deg == kFovUnknown) {
float film_width_inches = cam.FilmWidth();
float focal_length_mm = cam.FocalLength();
ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
} else {
// FBX fov is full-view degrees. We want half-view radians.
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
}
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
out_camera->mClipPlaneNear = cam.NearPlane(); out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane(); out_camera->mClipPlaneFar = cam.FarPlane();
} }
@ -640,7 +658,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
const auto zero_epsilon = ai_epsilon; const auto zero_epsilon = Math::getEpsilon<ai_real>();
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -873,8 +891,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
data->Set(index++, prop.first, interpretedBool->Value()); data->Set(index++, prop.first, interpretedBool->Value());
} else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) { } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
data->Set(index++, prop.first, interpretedInt->Value()); data->Set(index++, prop.first, interpretedInt->Value());
} else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
data->Set(index++, prop.first, interpretedUInt->Value());
} else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) { } else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
data->Set(index++, prop.first, interpretedUint64->Value()); data->Set(index++, prop.first, interpretedUint64->Value());
} else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
data->Set(index++, prop.first, interpretedint64->Value());
} else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) { } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
data->Set(index++, prop.first, interpretedFloat->Value()); data->Set(index++, prop.first, interpretedFloat->Value());
} else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) { } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
@ -1176,15 +1198,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto &curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto &curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
//losing channel name if using shapeGeometry->Name() //losing channel name if using shapeGeometry->Name()
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name())); // if blendShapeChannel Name is empty or don't have a ".", add geoMetryName;
auto aniName = FixAnimMeshName(blendShapeChannel->Name());
auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
if (aniName.empty()) {
aniName = geoMetryName;
}
else if (aniName.find('.') == aniName.npos) {
aniName += "." + geoMetryName;
}
animMesh->mName.Set(aniName);
for (size_t j = 0; j < curIndices.size(); j++) { for (size_t j = 0; j < curIndices.size(); j++) {
const unsigned int curIndex = curIndices.at(j); const unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j); aiVector3D vertex = curVertices.at(j);
@ -1406,13 +1436,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto& curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto& curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto& curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
for (size_t j = 0; j < curIndices.size(); j++) { for (size_t j = 0; j < curIndices.size(); j++) {
unsigned int curIndex = curIndices.at(j); unsigned int curIndex = curIndices.at(j);
@ -1455,7 +1484,9 @@ static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *s
skeletonBone->mWeights = bone->mWeights; skeletonBone->mWeights = bone->mWeights;
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix; skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
skeletonBone->mMeshId = mesh; skeletonBone->mMeshId = mesh;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
skeletonBone->mNode = bone->mNode; skeletonBone->mNode = bone->mNode;
#endif
skeletonBone->mParent = -1; skeletonBone->mParent = -1;
} }

View File

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

View File

@ -243,7 +243,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Document::Document(const Parser& parser, const ImportSettings& settings) : Document::Document(Parser& parser, const ImportSettings& settings) :
settings(settings), parser(parser) { settings(settings), parser(parser) {
ASSIMP_LOG_DEBUG("Creating FBX Document"); ASSIMP_LOG_DEBUG("Creating FBX Document");
@ -265,13 +265,17 @@ Document::Document(const Parser& parser, const ImportSettings& settings) :
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Document::~Document() { Document::~Document()
for(ObjectMap::value_type& v : objects) { {
delete v.second; // The document does not own the memory for the following objects, but we need to call their d'tor
// so they can properly free memory like string members:
for (ObjectMap::value_type &v : objects) {
delete_LazyObject(v.second);
} }
for(ConnectionMap::value_type& v : src_connections) { for (ConnectionMap::value_type &v : src_connections) {
delete v.second; delete_Connection(v.second);
} }
// |dest_connections| contain the same Connection objects as the |src_connections| // |dest_connections| contain the same Connection objects as the |src_connections|
} }
@ -356,9 +360,11 @@ void Document::ReadObjects() {
DOMError("no Objects dictionary found"); DOMError("no Objects dictionary found");
} }
StackAllocator &allocator = parser.GetAllocator();
// add a dummy entry to represent the Model::RootNode object (id 0), // add a dummy entry to represent the Model::RootNode object (id 0),
// which is only indirectly defined in the input file // which is only indirectly defined in the input file
objects[0] = new LazyObject(0L, *eobjects, *this); objects[0] = new_LazyObject(0L, *eobjects, *this);
const Scope& sobjects = *eobjects->Compound(); const Scope& sobjects = *eobjects->Compound();
for(const ElementMap::value_type& el : sobjects.Elements()) { for(const ElementMap::value_type& el : sobjects.Elements()) {
@ -381,11 +387,13 @@ void Document::ReadObjects() {
DOMError("encountered object with implicitly defined id 0",el.second); DOMError("encountered object with implicitly defined id 0",el.second);
} }
if(objects.find(id) != objects.end()) { const auto foundObject = objects.find(id);
if(foundObject != objects.end()) {
DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
delete foundObject->second;
} }
objects[id] = new LazyObject(id, *el.second, *this); objects[id] = new_LazyObject(id, *el.second, *this);
// grab all animation stacks upfront since there is no listing of them // grab all animation stacks upfront since there is no listing of them
if(!strcmp(el.first.c_str(),"AnimationStack")) { if(!strcmp(el.first.c_str(),"AnimationStack")) {
@ -452,8 +460,10 @@ void Document::ReadPropertyTemplates() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Document::ReadConnections() { void Document::ReadConnections()
const Scope& sc = parser.GetRootScope(); {
StackAllocator &allocator = parser.GetAllocator();
const Scope &sc = parser.GetRootScope();
// read property templates from "Definitions" section // read property templates from "Definitions" section
const Element* const econns = sc["Connections"]; const Element* const econns = sc["Connections"];
if(!econns || !econns->Compound()) { if(!econns || !econns->Compound()) {
@ -492,7 +502,7 @@ void Document::ReadConnections() {
} }
// add new connection // add new connection
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this); const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
src_connections.insert(ConnectionMap::value_type(src,c)); src_connections.insert(ConnectionMap::value_type(src,c));
dest_connections.insert(ConnectionMap::value_type(dest,c)); dest_connections.insert(ConnectionMap::value_type(dest,c));
} }

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_DOCUMENT_H #define INCLUDED_AI_FBX_DOCUMENT_H
#include <numeric> #include <numeric>
#include <unordered_set>
#include <stdint.h> #include <stdint.h>
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include "FBXProperties.h" #include "FBXProperties.h"
@ -54,9 +55,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _AI_CONCAT(a,b) a ## b #define _AI_CONCAT(a,b) a ## b
#define AI_CONCAT(a,b) _AI_CONCAT(a,b) #define AI_CONCAT(a,b) _AI_CONCAT(a,b)
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
// Use an 'illegal' default FOV value to detect if the FBX camera has set the FOV.
static const float kFovUnknown = -1.0f;
class Parser; class Parser;
class Object; class Object;
struct ImportSettings; struct ImportSettings;
@ -80,6 +86,10 @@ class BlendShape;
class Skin; class Skin;
class Cluster; class Cluster;
#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
#define delete_LazyObject(_p) (_p)->~LazyObject()
#define delete_Connection(_p) (_p)->~Connection()
/** Represents a delay-parsed FBX objects. Many objects in the scene /** Represents a delay-parsed FBX objects. Many objects in the scene
* are not needed by assimp, so it makes no sense to parse them * are not needed by assimp, so it makes no sense to parse them
@ -242,7 +252,7 @@ public:
fbx_simple_property(FilmAspectRatio, float, 1.0f) fbx_simple_property(FilmAspectRatio, float, 1.0f)
fbx_simple_property(ApertureMode, int, 0) fbx_simple_property(ApertureMode, int, 0)
fbx_simple_property(FieldOfView, float, 1.0f) fbx_simple_property(FieldOfView, float, kFovUnknown)
fbx_simple_property(FocalLength, float, 1.0f) fbx_simple_property(FocalLength, float, 1.0f)
}; };
@ -855,14 +865,14 @@ public:
return fullWeights; return fullWeights;
} }
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const { const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
return shapeGeometries; return shapeGeometries;
} }
private: private:
float percent; float percent;
WeightArray fullWeights; WeightArray fullWeights;
std::vector<const ShapeGeometry*> shapeGeometries; std::unordered_set<const ShapeGeometry*> shapeGeometries;
}; };
/** DOM class for BlendShape deformers */ /** DOM class for BlendShape deformers */
@ -872,12 +882,12 @@ public:
virtual ~BlendShape(); virtual ~BlendShape();
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const { const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
return blendShapeChannels; return blendShapeChannels;
} }
private: private:
std::vector<const BlendShapeChannel*> blendShapeChannels; std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
}; };
/** DOM class for skin deformer clusters (aka sub-deformers) */ /** DOM class for skin deformer clusters (aka sub-deformers) */
@ -1072,7 +1082,7 @@ private:
/** DOM root for a FBX file */ /** DOM root for a FBX file */
class Document { class Document {
public: public:
Document(const Parser& parser, const ImportSettings& settings); Document(Parser& parser, const ImportSettings& settings);
~Document(); ~Document();
@ -1156,7 +1166,7 @@ private:
const ImportSettings& settings; const ImportSettings& settings;
ObjectMap objects; ObjectMap objects;
const Parser& parser; Parser& parser;
PropertyTemplateMap templates; PropertyTemplateMap templates;
ConnectionMap src_connections; ConnectionMap src_connections;

View File

@ -360,7 +360,7 @@ void FBX::Node::EndBinary(
bool has_children bool has_children
) { ) {
// if there were children, add a null record // if there were children, add a null record
if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); } if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD_STRING); }
// now go back and write initial pos // now go back and write initial pos
this->end_pos = s.Tell(); this->end_pos = s.Tell();

View File

@ -77,8 +77,6 @@ public: // constructors
/// The class constructor with the name. /// The class constructor with the name.
Node(const std::string& n) Node(const std::string& n)
: name(n) : name(n)
, properties()
, children()
, force_has_children( false ) { , force_has_children( false ) {
// empty // empty
} }
@ -87,8 +85,6 @@ public: // constructors
template <typename... More> template <typename... More>
Node(const std::string& n, More&&... more) Node(const std::string& n, More&&... more)
: name(n) : name(n)
, properties()
, children()
, force_has_children(false) { , force_has_children(false) {
AddProperties(std::forward<More>(more)...); AddProperties(std::forward<More>(more)...);
} }

View File

@ -62,8 +62,7 @@ namespace Assimp {
template <> template <>
const char *LogFunctions<FBXImporter>::Prefix() { const char *LogFunctions<FBXImporter>::Prefix() {
static auto prefix = "FBX: "; return "FBX: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp
@ -90,10 +89,7 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer // Constructor to be privately used by #Importer
FBXImporter::FBXImporter() : FBXImporter::FBXImporter() = default;
mSettings() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
@ -156,19 +152,19 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// broad-phase tokenized pass in which we identify the core // broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens; TokenList tokens;
Assimp::StackAllocator tempAllocator;
try { try {
bool is_binary = false; bool is_binary = false;
if (!strncmp(begin, "Kaydara FBX Binary", 18)) { if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
is_binary = true; is_binary = true;
TokenizeBinary(tokens, begin, contents.size()); TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
} else { } else {
Tokenize(tokens, begin); Tokenize(tokens, begin, tempAllocator);
} }
// use this information to construct a very rudimentary // use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure // parse-tree representing the FBX scope structure
Parser parser(tokens, is_binary); Parser parser(tokens, tempAllocator, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, mSettings); Document doc(parser, mSettings);
@ -187,9 +183,11 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// assimp universal format (M) // assimp universal format (M)
SetFileScale(size_relative_to_cm * 0.01f); SetFileScale(size_relative_to_cm * 0.01f);
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); // This collection does not own the memory for the tokens, but we need to call their d'tor
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
} catch (std::exception &) { } catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
throw; throw;
} }
} }

View File

@ -138,20 +138,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Material::~Material() = default; Material::~Material() = default;
aiVector2D uvTrans;
aiVector2D uvScaling;
ai_real uvRotation;
std::string type;
std::string relativeFileName;
std::string fileName;
std::string alphaSource;
std::shared_ptr<const PropertyTable> props;
unsigned int crop[4]{};
const Video* media;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
Object(id,element,name), Object(id,element,name),

View File

@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element); const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) { if (bsp) {
blendShapes.push_back(bsp); auto pr = blendShapes.insert(bsp);
if (!pr.second) {
FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
}
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
} }

View File

@ -2,8 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2023, assimp team
All rights reserved. All rights reserved.
@ -53,84 +52,101 @@ namespace Assimp {
namespace FBX { namespace FBX {
/** /**
* DOM base class for all kinds of FBX geometry * @brief DOM base class for all kinds of FBX geometry
*/ */
class Geometry : public Object { class Geometry : public Object {
public: public:
/// @brief The class constructor with all parameters. /// @brief The class constructor with all parameters.
/// @param id The id. /// @param id The id.
/// @param element /// @param element The element instance
/// @param name /// @param name The name instance
/// @param doc /// @param doc The document instance
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/// @brief The class destructor, default.
virtual ~Geometry() = default; virtual ~Geometry() = default;
/// Get the Skin attached to this geometry or nullptr /// @brief Get the Skin attached to this geometry or nullptr.
/// @return The deformer skip instance as a pointer, nullptr if none.
const Skin* DeformerSkin() const; const Skin* DeformerSkin() const;
/// Get the BlendShape attached to this geometry or nullptr /// @brief Get the BlendShape attached to this geometry or nullptr
const std::vector<const BlendShape*>& GetBlendShapes() const; /// @return The blendshape arrays.
const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
private: private:
const Skin* skin; const Skin* skin;
std::vector<const BlendShape*> blendShapes; std::unordered_set<const BlendShape*> blendShapes;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;
/** /**
* DOM class for FBX geometry of type "Mesh" * @brief DOM class for FBX geometry of type "Mesh"
*/ */
class MeshGeometry : public Geometry { class MeshGeometry : public Geometry {
public: public:
/** The class constructor */ /// @brief The class constructor
/// @param id The id.
/// @param element The element instance
/// @param name The name instance
/// @param doc The document instance
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/** The class destructor */ /// @brief The class destructor, default.
virtual ~MeshGeometry() = default; virtual ~MeshGeometry() = default;
/** Get a list of all vertex points, non-unique*/ /// brief Get a vector of all vertex points, non-unique.
/// @return The vertices vector.
const std::vector<aiVector3D>& GetVertices() const; const std::vector<aiVector3D>& GetVertices() const;
/** Get a list of all vertex normals or an empty array if /// @brief Get a vector of all vertex normals or an empty array if no normals are specified.
* no normals are specified. */ /// @return The normal vector.
const std::vector<aiVector3D>& GetNormals() const; const std::vector<aiVector3D>& GetNormals() const;
/** Get a list of all vertex tangents or an empty array /// @brief Get a vector of all vertex tangents or an empty array if no tangents are specified.
* if no tangents are specified */ /// @return The vertex tangents vector.
const std::vector<aiVector3D>& GetTangents() const; const std::vector<aiVector3D>& GetTangents() const;
/** Get a list of all vertex bi-normals or an empty array /// @brief Get a vector of all vertex bi-normals or an empty array if no bi-normals are specified.
* if no bi-normals are specified */ /// @return The binomal vector.
const std::vector<aiVector3D>& GetBinormals() const; const std::vector<aiVector3D>& GetBinormals() const;
/** Return list of faces - each entry denotes a face and specifies /// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
* how many vertices it has. Vertices are taken from the /// Vertices are taken from the vertex data arrays in sequential order.
* vertex data arrays in sequential order. */ /// @return The face indices vector.
const std::vector<unsigned int>& GetFaceIndexCounts() const; const std::vector<unsigned int>& GetFaceIndexCounts() const;
/** Get a UV coordinate slot, returns an empty array if /// @brief Get a UV coordinate slot, returns an empty array if the requested slot does not exist.
* the requested slot does not exist. */ /// @param index The requested texture coordinate slot.
/// @return The texture coordinates.
const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const; const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const;
/** Get a UV coordinate slot, returns an empty array if /// @brief Get a UV coordinate slot, returns an empty array if the requested slot does not exist.
* the requested slot does not exist. */ /// @param index The requested texture coordinate slot.
/// @return The texture coordinate channel name.
std::string GetTextureCoordChannelName( unsigned int index ) const; std::string GetTextureCoordChannelName( unsigned int index ) const;
/** Get a vertex color coordinate slot, returns an empty array if /// @brief Get a vertex color coordinate slot, returns an empty array if the requested slot does not exist.
* the requested slot does not exist. */ /// @param index The requested texture coordinate slot.
/// @return The vertex color vector.
const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const; const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const;
/** Get per-face-vertex material assignments */ /// @brief Get per-face-vertex material assignments.
/// @return The Material indices Array.
const MatIndexArray& GetMaterialIndices() const; const MatIndexArray& GetMaterialIndices() const;
/** Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr /// @brief Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr if the vertex index is not valid.
* if the vertex index is not valid. */ /// @param in_index The requested input index.
/// @param count The number of indices.
/// @return The indices.
const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const; const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const;
/** Determine the face to which a particular output vertex index belongs. /// @brief Determine the face to which a particular output vertex index belongs.
* This mapping is always unique. */ /// This mapping is always unique.
/// @param in_index The requested input index.
/// @return The face-to-vertex index.
unsigned int FaceForVertexIndex( unsigned int in_index ) const; unsigned int FaceForVertexIndex( unsigned int in_index ) const;
private: private:

View File

@ -88,6 +88,7 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void ParseError(const std::string& message, TokenPtr token) AI_WONT_RETURN_SUFFIX;
void ParseError(const std::string& message, TokenPtr token) void ParseError(const std::string& message, TokenPtr token)
{ {
if(token) { if(token) {
@ -115,8 +116,11 @@ namespace Assimp {
namespace FBX { namespace FBX {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { Element::Element(const Token& key_token, Parser& parser) :
key_token(key_token), compound(nullptr)
{
TokenPtr n = nullptr; TokenPtr n = nullptr;
StackAllocator &allocator = parser.GetAllocator();
do { do {
n = parser.AdvanceToNextToken(); n = parser.AdvanceToNextToken();
if(!n) { if(!n) {
@ -145,7 +149,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
} }
if (n->Type() == TokenType_OPEN_BRACKET) { if (n->Type() == TokenType_OPEN_BRACKET) {
compound.reset(new Scope(parser)); compound = new_Scope(parser);
// current token should be a TOK_CLOSE_BRACKET // current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken(); n = parser.CurrentToken();
@ -163,6 +167,15 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Element::~Element()
{
if (compound) {
delete_Scope(compound);
}
// no need to delete tokens, they are owned by the parser
}
Scope::Scope(Parser& parser,bool topLevel) Scope::Scope(Parser& parser,bool topLevel)
{ {
if(!topLevel) { if(!topLevel) {
@ -172,6 +185,7 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
} }
StackAllocator &allocator = parser.GetAllocator();
TokenPtr n = parser.AdvanceToNextToken(); TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) { if (n == nullptr) {
ParseError("unexpected end of file"); ParseError("unexpected end of file");
@ -188,36 +202,45 @@ Scope::Scope(Parser& parser,bool topLevel)
ParseError("unexpected content: empty string."); ParseError("unexpected content: empty string.");
} }
elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); auto *element = new_Element(*n, parser);
// Element() should stop at the next Key token (or right after a Close token) // Element() should stop at the next Key token (or right after a Close token)
n = parser.CurrentToken(); n = parser.CurrentToken();
if (n == nullptr) { if (n == nullptr) {
if (topLevel) { if (topLevel) {
elements.insert(ElementMap::value_type(str, element));
return; return;
} }
delete_Element(element);
ParseError("unexpected end of file",parser.LastToken()); ParseError("unexpected end of file",parser.LastToken());
} else {
elements.insert(ElementMap::value_type(str, element));
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::~Scope() { Scope::~Scope()
for(ElementMap::value_type& v : elements) { {
delete v.second; // This collection does not own the memory for the elements, but we need to call their d'tor:
for (ElementMap::value_type &v : elements) {
delete_Element(v.second);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Parser::Parser (const TokenList& tokens, bool is_binary) Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
: tokens(tokens) tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
, last()
, current()
, cursor(tokens.begin())
, is_binary(is_binary)
{ {
ASSIMP_LOG_DEBUG("Parsing FBX tokens"); ASSIMP_LOG_DEBUG("Parsing FBX tokens");
root.reset(new Scope(*this,true)); root = new_Scope(*this, true);
}
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
delete_Scope(root);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/LogAux.h> #include <assimp/LogAux.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include "Common/StackAllocator.h"
#include "FBXCompileConfig.h" #include "FBXCompileConfig.h"
#include "FBXTokenizer.h" #include "FBXTokenizer.h"
@ -63,14 +64,14 @@ class Parser;
class Element; class Element;
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03 // XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef std::vector< Scope* > ScopeList; using ScopeList = std::vector<Scope*>;
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
# define new_Scope new Scope
# define new_Element new Element
#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
#define new_Element new (allocator.Allocate(sizeof(Element))) Element
#define delete_Scope(_p) (_p)->~Scope()
#define delete_Element(_p) (_p)->~Element()
/** FBX data entity that consists of a key:value tuple. /** FBX data entity that consists of a key:value tuple.
* *
@ -82,15 +83,16 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
* @endverbatim * @endverbatim
* *
* As can be seen in this sample, elements can contain nested #Scope * As can be seen in this sample, elements can contain nested #Scope
* as their trailing member. **/ * as their trailing member.
**/
class Element class Element
{ {
public: public:
Element(const Token& key_token, Parser& parser); Element(const Token& key_token, Parser& parser);
~Element() = default; ~Element();
const Scope* Compound() const { const Scope* Compound() const {
return compound.get(); return compound;
} }
const Token& KeyToken() const { const Token& KeyToken() const {
@ -104,7 +106,7 @@ public:
private: private:
const Token& key_token; const Token& key_token;
TokenList tokens; TokenList tokens;
std::unique_ptr<Scope> compound; Scope* compound;
}; };
/** FBX data entity that consists of a 'scope', a collection /** FBX data entity that consists of a 'scope', a collection
@ -159,8 +161,8 @@ class Parser
public: public:
/** Parse given a token list. Does not take ownership of the tokens - /** Parse given a token list. Does not take ownership of the tokens -
* the objects must persist during the entire parser lifetime */ * the objects must persist during the entire parser lifetime */
Parser (const TokenList& tokens,bool is_binary); Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary);
~Parser() = default; ~Parser();
const Scope& GetRootScope() const { const Scope& GetRootScope() const {
return *root; return *root;
@ -170,6 +172,10 @@ public:
return is_binary; return is_binary;
} }
StackAllocator &GetAllocator() {
return allocator;
}
private: private:
friend class Scope; friend class Scope;
friend class Element; friend class Element;
@ -180,10 +186,10 @@ private:
private: private:
const TokenList& tokens; const TokenList& tokens;
StackAllocator &allocator;
TokenPtr last, current; TokenPtr last, current;
TokenList::const_iterator cursor; TokenList::const_iterator cursor;
std::unique_ptr<Scope> root; Scope *root;
const bool is_binary; const bool is_binary;
}; };

View File

@ -94,7 +94,8 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line,
// process a potential data token up to 'cur', adding it to 'output_tokens'. // process a potential data token up to 'cur', adding it to 'output_tokens'.
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end, void ProcessDataToken(TokenList &output_tokens, StackAllocator &token_allocator,
const char*& start, const char*& end,
unsigned int line, unsigned int line,
unsigned int column, unsigned int column,
TokenType type = TokenType_DATA, TokenType type = TokenType_DATA,
@ -131,8 +132,7 @@ void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Tokenize(TokenList& output_tokens, const char* input) void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
{
ai_assert(input); ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file"); ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
@ -164,7 +164,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
in_double_quotes = false; in_double_quotes = false;
token_end = cur; token_end = cur;
ProcessDataToken(output_tokens,token_begin,token_end,line,column); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
pending_data_token = false; pending_data_token = false;
} }
continue; continue;
@ -181,30 +181,30 @@ void Tokenize(TokenList& output_tokens, const char* input)
continue; continue;
case ';': case ';':
ProcessDataToken(output_tokens,token_begin,token_end,line,column); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
comment = true; comment = true;
continue; continue;
case '{': case '{':
ProcessDataToken(output_tokens,token_begin,token_end, line, column); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
continue; continue;
case '}': case '}':
ProcessDataToken(output_tokens,token_begin,token_end,line,column); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
continue; continue;
case ',': case ',':
if (pending_data_token) { if (pending_data_token) {
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
} }
output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column)); output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
continue; continue;
case ':': case ':':
if (pending_data_token) { if (pending_data_token) {
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
} }
else { else {
TokenizeError("unexpected colon", line, column); TokenizeError("unexpected colon", line, column);
@ -226,7 +226,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
} }
} }
ProcessDataToken(output_tokens,token_begin,token_end,line,column,type); ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
} }
pending_data_token = false; pending_data_token = false;

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_TOKENIZER_H #define INCLUDED_AI_FBX_TOKENIZER_H
#include "FBXCompileConfig.h" #include "FBXCompileConfig.h"
#include "Common/StackAllocator.h"
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/defs.h> #include <assimp/defs.h>
#include <vector> #include <vector>
@ -154,11 +155,11 @@ private:
const unsigned int column; const unsigned int column;
}; };
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef const Token* TokenPtr; typedef const Token* TokenPtr;
typedef std::vector< TokenPtr > TokenList; typedef std::vector< TokenPtr > TokenList;
#define new_Token new Token #define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
#define delete_Token(_p) (_p)->~Token()
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens. /** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
@ -168,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList;
* @param output_tokens Receives a list of all tokens in the input data. * @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated. * @param input_buffer Textual input buffer to be processed, 0-terminated.
* @throw DeadlyImportError if something goes wrong */ * @throw DeadlyImportError if something goes wrong */
void Tokenize(TokenList& output_tokens, const char* input); void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &tokenAllocator);
/** Tokenizer function for binary FBX files. /** Tokenizer function for binary FBX files.
@ -179,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
* @param input_buffer Binary input buffer to be processed. * @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal. * @param length Length of input buffer, in bytes. There is no 0-terminal.
* @throw DeadlyImportError if something goes wrong */ * @throw DeadlyImportError if something goes wrong */
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length); void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &tokenAllocator);
} // ! FBX } // ! FBX

View File

@ -66,6 +66,17 @@ struct delete_fun
} }
}; };
/** helper for std::for_each to call the destructor on all items in a container without freeing their heap*/
template <typename T>
struct destructor_fun {
void operator()(const volatile T* del) {
if (del) {
del->~T();
}
}
};
/** Get a string representation for a #TokenType. */ /** Get a string representation for a #TokenType. */
const char* TokenTypeString(TokenType t); const char* TokenTypeString(TokenType t);

View File

@ -115,7 +115,9 @@ void HMPImporter::InternReadFile(const std::string &pFile,
throw DeadlyImportError("HMP File is too small."); throw DeadlyImportError("HMP File is too small.");
// Allocate storage and copy the contents of the file to a memory buffer // Allocate storage and copy the contents of the file to a memory buffer
mBuffer = new uint8_t[fileSize]; auto deleter=[this](uint8_t* ptr){ delete[] ptr; mBuffer = nullptr; };
std::unique_ptr<uint8_t[], decltype(deleter)> buffer(new uint8_t[fileSize], deleter);
mBuffer = buffer.get();
file->Read((void *)mBuffer, 1, fileSize); file->Read((void *)mBuffer, 1, fileSize);
iFileSize = (unsigned int)fileSize; iFileSize = (unsigned int)fileSize;
@ -143,9 +145,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
// Print the magic word to the logger // Print the magic word to the logger
std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic)); std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic));
delete[] mBuffer;
mBuffer = nullptr;
// We're definitely unable to load this file // We're definitely unable to load this file
throw DeadlyImportError("Unknown HMP subformat ", pFile, throw DeadlyImportError("Unknown HMP subformat ", pFile,
". Magic word (", szBuffer, ") is not known"); ". Magic word (", szBuffer, ") is not known");
@ -153,9 +152,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
// Set the AI_SCENE_FLAGS_TERRAIN bit // Set the AI_SCENE_FLAGS_TERRAIN bit
pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN; pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN;
delete[] mBuffer;
mBuffer = nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -445,11 +441,11 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
szCursor += sizeof(uint32_t); szCursor += sizeof(uint32_t);
// allocate an output material // allocate an output material
aiMaterial *pcMat = new aiMaterial(); std::unique_ptr<aiMaterial> pcMat(new aiMaterial());
// read the skin, this works exactly as for MDL7 // read the skin, this works exactly as for MDL7
ParseSkinLump_3DGS_MDL7(szCursor, &szCursor, ParseSkinLump_3DGS_MDL7(szCursor, &szCursor,
pcMat, iType, iWidth, iHeight); pcMat.get(), iType, iWidth, iHeight);
// now we need to skip any other skins ... // now we need to skip any other skins ...
for (unsigned int i = 1; i < iNumSkins; ++i) { for (unsigned int i = 1; i < iNumSkins; ++i) {
@ -468,7 +464,7 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
// setup the material ... // setup the material ...
pScene->mNumMaterials = 1; pScene->mNumMaterials = 1;
pScene->mMaterials = new aiMaterial *[1]; pScene->mMaterials = new aiMaterial *[1];
pScene->mMaterials[0] = pcMat; pScene->mMaterials[0] = pcMat.release();
*szCursorOut = szCursor; *szCursorOut = szCursor;
} }

View File

@ -86,7 +86,7 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Import a HMP4 file /** Import a HMP4 file
*/ */
void InternReadFile_HMP4(); AI_WONT_RETURN void InternReadFile_HMP4() AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Import a HMP5 file /** Import a HMP5 file

View File

@ -73,8 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
template <> template <>
const char *LogFunctions<IFCImporter>::Prefix() { const char *LogFunctions<IFCImporter>::Prefix() {
static auto prefix = "IFC: "; return "IFC: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp

View File

@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetLib/IFC/IFCUtil.h" #include "AssetLib/IFC/IFCUtil.h"
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "Geometry/GeometryUtils.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
namespace Assimp { namespace Assimp {
@ -235,7 +236,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
struct CompareVector { struct CompareVector {
bool operator () (const IfcVector3& a, const IfcVector3& b) const { bool operator () (const IfcVector3& a, const IfcVector3& b) const {
IfcVector3 d = a - b; IfcVector3 d = a - b;
IfcFloat eps = ai_epsilon; constexpr IfcFloat eps = ai_epsilon;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps); return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
} }
}; };

View File

@ -43,6 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the Irr importer class * @brief Implementation of the Irr importer class
*/ */
#include "assimp/Exceptional.h"
#include "assimp/StringComparison.h"
#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER #ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
#include "AssetLib/Irr/IRRLoader.h" #include "AssetLib/Irr/IRRLoader.h"
@ -62,8 +64,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
@ -239,7 +239,7 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial *> &materials,
// Do we have a default material? If not we need to create one // Do we have a default material? If not we need to create one
if (UINT_MAX == defMatIdx) { if (UINT_MAX == defMatIdx) {
defMatIdx = (unsigned int)materials.size(); defMatIdx = (unsigned int)materials.size();
//TODO: add this materials to someone? // TODO: add this materials to someone?
/*aiMaterial* mat = new aiMaterial(); /*aiMaterial* mat = new aiMaterial();
aiString s; aiString s;
@ -380,7 +380,6 @@ void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNode
if (360 == lcm) if (360 == lcm)
break; break;
// find out how many time units we'll need for the finest // find out how many time units we'll need for the finest
// track (in seconds) - this defines the number of output // track (in seconds) - this defines the number of output
// keys (fps * seconds) // keys (fps * seconds)
@ -609,7 +608,7 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
std::vector<aiMaterial *> &materials, std::vector<aiMaterial *> &materials,
unsigned int &defMatIdx) { unsigned int &defMatIdx) {
unsigned int oldMeshSize = (unsigned int)meshes.size(); unsigned int oldMeshSize = (unsigned int)meshes.size();
//unsigned int meshTrafoAssign = 0; // unsigned int meshTrafoAssign = 0;
// Now determine the type of the node // Now determine the type of the node
switch (root->type) { switch (root->type) {
@ -797,7 +796,7 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
// Now compute the final local transformation matrix of the // Now compute the final local transformation matrix of the
// node from the given translation, rotation and scaling values. // node from the given translation, rotation and scaling values.
// (the rotation is given in Euler angles, XYZ order) // (the rotation is given in Euler angles, XYZ order)
//std::swap((float&)root->rotation.z,(float&)root->rotation.y); // std::swap((float&)root->rotation.z,(float&)root->rotation.y);
rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation)); rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation));
// apply scaling // apply scaling
@ -836,175 +835,164 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} }
} }
// ------------------------------------------------------------------------------------------------ void IRRImporter::ParseNodeAttributes(pugi::xml_node &attributesNode, IRRImporter::Node *nd, BatchLoader &batch) {
// Imports the given file into the given scene structure. ai_assert(!ASSIMP_stricmp(attributesNode.name(), "attributes")); // Node must be <attributes>
void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { ai_assert(nd != nullptr); // dude
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file // Big switch statement that tests for various tags inside <attributes>
if (file == nullptr) { // and applies them to nd
throw DeadlyImportError("Failed to open IRR file ", pFile); // I don't believe nodes have boolean attributes
for (pugi::xml_node &attribute : attributesNode.children()) {
if (attribute.type() != pugi::node_element) continue;
if (!ASSIMP_stricmp(attribute.name(), "vector3d")) { // <vector3d />
VectorProperty prop;
ReadVectorProperty(prop, attribute);
if (prop.name == "Position") {
nd->position = prop.value;
} else if (prop.name == "Rotation") {
nd->rotation = prop.value;
} else if (prop.name == "Scale") {
nd->scaling = prop.value;
} else if (Node::CAMERA == nd->type) {
aiCamera *cam = cameras.back();
if (prop.name == "Target") {
cam->mLookAt = prop.value;
} else if (prop.name == "UpVector") {
cam->mUp = prop.value;
} }
// Construct the irrXML parser
XmlParser st;
if (!st.parse( file.get() )) {
throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
} }
pugi::xml_node rootElement = st.getRootNode(); } else if (!ASSIMP_stricmp(attribute.name(), "float")) { // <float />
FloatProperty prop;
// The root node of the scene ReadFloatProperty(prop, attribute);
Node *root = new Node(Node::DUMMY); if (prop.name == "FramesPerSecond" && Node::ANIMMESH == nd->type) {
root->parent = nullptr; nd->framesPerSecond = prop.value;
root->name = "<IRRSceneRoot>"; } else if (Node::CAMERA == nd->type) {
/* This is the vertical, not the horizontal FOV.
// Current node parent * We need to compute the right FOV from the
Node *curParent = root; * screen aspect which we don't know yet.
// Scene-graph node we're currently working on
Node *curNode = nullptr;
// List of output cameras
std::vector<aiCamera *> cameras;
// List of output lights
std::vector<aiLight *> lights;
// Batch loader used to load external models
BatchLoader batch(pIOHandler);
//batch.SetBasePath(pFile);
cameras.reserve(5);
lights.reserve(5);
bool inMaterials = false, inAnimator = false;
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
// Parse the XML file
//while (reader->read()) {
for (pugi::xml_node child : rootElement.children())
switch (child.type()) {
case pugi::node_element:
if (!ASSIMP_stricmp(child.name(), "node")) {
// ***********************************************************************
/* What we're going to do with the node depends
* on its type:
*
* "mesh" - Load a mesh from an external file
* "cube" - Generate a cube
* "skybox" - Generate a skybox
* "light" - A light source
* "sphere" - Generate a sphere mesh
* "animatedMesh" - Load an animated mesh from an external file
* and join its animation channels with ours.
* "empty" - A dummy node
* "camera" - A camera
* "terrain" - a terrain node (data comes from a heightmap)
* "billboard", ""
*
* Each of these nodes can be animated and all can have multiple
* materials assigned (except lights, cameras and dummies, of course).
*/ */
// *********************************************************************** if (prop.name == "Fovy") {
//const char *sz = reader->getAttributeValueSafe("type"); cameras.back()->mHorizontalFOV = prop.value;
pugi::xml_attribute attrib = child.attribute("type"); } else if (prop.name == "Aspect") {
Node *nd; cameras.back()->mAspect = prop.value;
if (!ASSIMP_stricmp(attrib.name(), "mesh") || !ASSIMP_stricmp(attrib.name(), "octTree")) { } else if (prop.name == "ZNear") {
// OctTree's and meshes are treated equally cameras.back()->mClipPlaneNear = prop.value;
nd = new Node(Node::MESH); } else if (prop.name == "ZFar") {
} else if (!ASSIMP_stricmp(attrib.name(), "cube")) { cameras.back()->mClipPlaneFar = prop.value;
nd = new Node(Node::CUBE); }
++guessedMeshCnt; } else if (Node::LIGHT == nd->type) {
} else if (!ASSIMP_stricmp(attrib.name(), "skybox")) { /* Additional light information
nd = new Node(Node::SKYBOX); */
guessedMeshCnt += 6; if (prop.name == "Attenuation") {
} else if (!ASSIMP_stricmp(attrib.name(), "camera")) { lights.back()->mAttenuationLinear = prop.value;
nd = new Node(Node::CAMERA); } else if (prop.name == "OuterCone") {
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
} else if (prop.name == "InnerCone") {
lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
}
}
// radius of the sphere to be generated -
// or alternatively, size of the cube
else if ((Node::SPHERE == nd->type && prop.name == "Radius") ||
(Node::CUBE == nd->type && prop.name == "Size")) {
nd->sphereRadius = prop.value;
}
} else if (!ASSIMP_stricmp(attribute.name(), "int")) { // <int />
// Only sphere nodes make use of integer attributes
if (Node::SPHERE == nd->type) {
IntProperty prop;
ReadIntProperty(prop, attribute);
if (prop.name == "PolyCountX") {
nd->spherePolyCountX = prop.value;
} else if (prop.name == "PolyCountY") {
nd->spherePolyCountY = prop.value;
}
}
} else if (!ASSIMP_stricmp(attribute.name(), "string") || !ASSIMP_stricmp(attribute.name(), "enum")) { // <string /> or < enum />
StringProperty prop;
ReadStringProperty(prop, attribute);
if (prop.value.length() == 0) continue; // skip empty strings
if (prop.name == "Name") {
nd->name = prop.value;
// Setup a temporary name for the camera /* If we're either a camera or a light source
aiCamera *cam = new aiCamera(); * we need to update the name in the aiLight/
cam->mName.Set(nd->name); * aiCamera structure, too.
cameras.push_back(cam); */
} else if (!ASSIMP_stricmp(attrib.name(), "light")) { if (Node::CAMERA == nd->type) {
nd = new Node(Node::LIGHT); cameras.back()->mName.Set(prop.value);
} else if (Node::LIGHT == nd->type) {
lights.back()->mName.Set(prop.value);
}
} else if (Node::LIGHT == nd->type && "LightType" == prop.name) {
if (prop.value == "Spot")
lights.back()->mType = aiLightSource_SPOT;
else if (prop.value == "Point")
lights.back()->mType = aiLightSource_POINT;
else if (prop.value == "Directional")
lights.back()->mType = aiLightSource_DIRECTIONAL;
else {
// We won't pass the validation with aiLightSourceType_UNDEFINED,
// so we remove the light and replace it with a silly dummy node
delete lights.back();
lights.pop_back();
nd->type = Node::DUMMY;
// Setup a temporary name for the light ASSIMP_LOG_ERROR("Ignoring light of unknown type: ", prop.value);
aiLight *cam = new aiLight(); }
cam->mName.Set(nd->name); } else if ((prop.name == "Mesh" && Node::MESH == nd->type) ||
lights.push_back(cam); Node::ANIMMESH == nd->type) {
} else if (!ASSIMP_stricmp(attrib.name(), "sphere")) { /* This is the file name of the mesh - either
nd = new Node(Node::SPHERE); * animated or not. We need to make sure we setup
++guessedMeshCnt; * the correct post-processing settings here.
} else if (!ASSIMP_stricmp(attrib.name(), "animatedMesh")) { */
nd = new Node(Node::ANIMMESH); unsigned int pp = 0;
} else if (!ASSIMP_stricmp(attrib.name(), "empty")) { BatchLoader::PropertyMap map;
nd = new Node(Node::DUMMY);
} else if (!ASSIMP_stricmp(attrib.name(), "terrain")) { /* If the mesh is a static one remove all animations from the impor data
nd = new Node(Node::TERRAIN); */
} else if (!ASSIMP_stricmp(attrib.name(), "billBoard")) { if (Node::ANIMMESH != nd->type) {
// We don't support billboards, so ignore them pp |= aiProcess_RemoveComponent;
ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp"); SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
nd = new Node(Node::DUMMY); aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
}
/* TODO: maybe implement the protection against recursive
* loading calls directly in BatchLoader? The current
* implementation is not absolutely safe. A LWS and an IRR
* file referencing each other *could* cause the system to
* recurse forever.
*/
const std::string extension = GetExtension(prop.value);
if ("irr" == extension) {
ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
} else { } else {
ASSIMP_LOG_WARN("IRR: Found unknown node: ", attrib.name()); nd->id = batch.AddLoadRequest(prop.value, pp, &map);
nd->meshPath = prop.value;
/* We skip the contents of nodes we don't know.
* We parse the transformation and all animators
* and skip the rest.
*/
nd = new Node(Node::DUMMY);
} }
/* Attach the newly created node to the scene-graph
*/
curNode = nd;
nd->parent = curParent;
curParent->children.push_back(nd);
} else if (!ASSIMP_stricmp(child.name(), "materials")) {
inMaterials = true;
} else if (!ASSIMP_stricmp(child.name(), "animators")) {
inAnimator = true;
} else if (!ASSIMP_stricmp(child.name(), "attributes")) {
// We should have a valid node here
// FIX: no ... the scene root node is also contained in an attributes block
if (!curNode) {
continue;
} }
}
}
}
void IRRImporter::ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd) {
Animator *curAnim = nullptr; Animator *curAnim = nullptr;
// Make empty animator
// Materials can occur for nearly any type of node nd->animators.emplace_back();
if (inMaterials && curNode->type != Node::DUMMY) { curAnim = &nd->animators.back(); // Push it back
// This is a material description - parse it! pugi::xml_node attributes = animatorNode.child("attributes");
curNode->materials.emplace_back(); if (!attributes) {
std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back(); ASSIMP_LOG_WARN("Animator node does not contain attributes. ");
return;
p.first = ParseMaterial(p.second);
++guessedMatCnt;
continue;
} else if (inAnimator) {
// This is an animation path - add a new animator
// to the list.
curNode->animators.emplace_back();
curAnim = &curNode->animators.back();
++guessedAnimCnt;
} }
/* Parse all elements in the attributes block for (pugi::xml_node attrib : attributes.children()) {
* and process them. // XML may contain useless noes like CDATA
*/
// while (reader->read()) {
for (pugi::xml_node attrib : child.children()) {
if (attrib.type() == pugi::node_element) {
//if (reader->getNodeType() == EXN_ELEMENT) {
//if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
if (!ASSIMP_stricmp(attrib.name(), "vector3d")) { if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
VectorProperty prop; VectorProperty prop;
ReadVectorProperty(prop); ReadVectorProperty(prop, attrib);
if (inAnimator) {
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") { if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
// We store the rotation euler angles in 'direction' // We store the rotation euler angles in 'direction'
curAnim->direction = prop.value; curAnim->direction = prop.value;
@ -1041,36 +1029,20 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
curAnim->direction = prop.value; curAnim->direction = prop.value;
} }
} }
} else {
if (prop.name == "Position") {
curNode->position = prop.value;
} else if (prop.name == "Rotation") {
curNode->rotation = prop.value;
} else if (prop.name == "Scale") {
curNode->scaling = prop.value;
} else if (Node::CAMERA == curNode->type) {
aiCamera *cam = cameras.back();
if (prop.name == "Target") {
cam->mLookAt = prop.value;
} else if (prop.name == "UpVector") {
cam->mUp = prop.value;
}
}
}
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
} else if (!ASSIMP_stricmp(attrib.name(), "bool")) { } else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop, attrib);
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") { if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
curAnim->loop = prop.value; curAnim->loop = prop.value;
} }
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
} else if (!ASSIMP_stricmp(attrib.name(), "float")) { } else if (!ASSIMP_stricmp(attrib.name(), "float")) {
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop, attrib);
if (inAnimator) {
// The speed property exists for several animators // The speed property exists for several animators
if (prop.name == "Speed") { if (prop.name == "Speed") {
curAnim->speed = prop.value; curAnim->speed = prop.value;
@ -1079,126 +1051,20 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
} else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") { } else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
curAnim->tightness = prop.value; curAnim->tightness = prop.value;
} }
} else {
if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
curNode->framesPerSecond = prop.value;
} else if (Node::CAMERA == curNode->type) {
/* This is the vertical, not the horizontal FOV.
* We need to compute the right FOV from the
* screen aspect which we don't know yet.
*/
if (prop.name == "Fovy") {
cameras.back()->mHorizontalFOV = prop.value;
} else if (prop.name == "Aspect") {
cameras.back()->mAspect = prop.value;
} else if (prop.name == "ZNear") {
cameras.back()->mClipPlaneNear = prop.value;
} else if (prop.name == "ZFar") {
cameras.back()->mClipPlaneFar = prop.value;
}
} else if (Node::LIGHT == curNode->type) {
/* Additional light information
*/
if (prop.name == "Attenuation") {
lights.back()->mAttenuationLinear = prop.value;
} else if (prop.name == "OuterCone") {
lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
} else if (prop.name == "InnerCone") {
lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
}
}
// radius of the sphere to be generated -
// or alternatively, size of the cube
else if ((Node::SPHERE == curNode->type && prop.name == "Radius") || (Node::CUBE == curNode->type && prop.name == "Size")) {
curNode->sphereRadius = prop.value;
}
}
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
} else if (!ASSIMP_stricmp(attrib.name(), "int")) { } else if (!ASSIMP_stricmp(attrib.name(), "int")) {
IntProperty prop; IntProperty prop;
ReadIntProperty(prop); ReadIntProperty(prop, attrib);
if (inAnimator) {
if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") { if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
curAnim->timeForWay = prop.value; curAnim->timeForWay = prop.value;
} }
} else {
// sphere polygon numbers in each direction
if (Node::SPHERE == curNode->type) {
if (prop.name == "PolyCountX") {
curNode->spherePolyCountX = prop.value;
} else if (prop.name == "PolyCountY") {
curNode->spherePolyCountY = prop.value;
}
}
}
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
} else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) { } else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop, attrib);
if (prop.value.length()) {
if (prop.name == "Name") {
curNode->name = prop.value;
/* If we're either a camera or a light source if (prop.name == "Type") {
* we need to update the name in the aiLight/
* aiCamera structure, too.
*/
if (Node::CAMERA == curNode->type) {
cameras.back()->mName.Set(prop.value);
} else if (Node::LIGHT == curNode->type) {
lights.back()->mName.Set(prop.value);
}
} else if (Node::LIGHT == curNode->type && "LightType" == prop.name) {
if (prop.value == "Spot")
lights.back()->mType = aiLightSource_SPOT;
else if (prop.value == "Point")
lights.back()->mType = aiLightSource_POINT;
else if (prop.value == "Directional")
lights.back()->mType = aiLightSource_DIRECTIONAL;
else {
// We won't pass the validation with aiLightSourceType_UNDEFINED,
// so we remove the light and replace it with a silly dummy node
delete lights.back();
lights.pop_back();
curNode->type = Node::DUMMY;
ASSIMP_LOG_ERROR("Ignoring light of unknown type: ", prop.value);
}
} else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
Node::ANIMMESH == curNode->type) {
/* This is the file name of the mesh - either
* animated or not. We need to make sure we setup
* the correct post-processing settings here.
*/
unsigned int pp = 0;
BatchLoader::PropertyMap map;
/* If the mesh is a static one remove all animations from the impor data
*/
if (Node::ANIMMESH != curNode->type) {
pp |= aiProcess_RemoveComponent;
SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
}
/* TODO: maybe implement the protection against recursive
* loading calls directly in BatchLoader? The current
* implementation is not absolutely safe. A LWS and an IRR
* file referencing each other *could* cause the system to
* recurse forever.
*/
const std::string extension = GetExtension(prop.value);
if ("irr" == extension) {
ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
} else {
curNode->id = batch.AddLoadRequest(prop.value, pp, &map);
curNode->meshPath = prop.value;
}
} else if (inAnimator && prop.name == "Type") {
// type of the animator // type of the animator
if (prop.value == "rotation") { if (prop.value == "rotation") {
curAnim->type = Animator::ROTATION; curAnim->type = Animator::ROTATION;
@ -1216,42 +1082,168 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
} }
} }
} }
//} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) { }
} else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) {
break;
}
}
}
break;
/*case EXN_ELEMENT_END: IRRImporter::Node *IRRImporter::ParseNode(pugi::xml_node &node, BatchLoader &batch) {
// Parse <node> tags.
// <node> tags have various types
// <node> tags can contain <attribute>, <material>
// they can also contain other <node> tags, (and can reference other files as well?)
// ***********************************************************************
/* What we're going to do with the node depends
* on its type:
*
* "mesh" - Load a mesh from an external file
* "cube" - Generate a cube
* "skybox" - Generate a skybox
* "light" - A light source
* "sphere" - Generate a sphere mesh
* "animatedMesh" - Load an animated mesh from an external file
* and join its animation channels with ours.
* "empty" - A dummy node
* "camera" - A camera
* "terrain" - a terrain node (data comes from a heightmap)
* "billboard", ""
*
* Each of these nodes can be animated and all can have multiple
* materials assigned (except lights, cameras and dummies, of course).
* Said materials and animators are all collected at the bottom
*/
// ***********************************************************************
Node *nd;
pugi::xml_attribute nodeTypeAttrib = node.attribute("type");
if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "mesh") || !ASSIMP_stricmp(nodeTypeAttrib.value(), "octTree")) {
// OctTree's and meshes are treated equally
nd = new Node(Node::MESH);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "cube")) {
nd = new Node(Node::CUBE);
guessedMeshCnt += 1; // Cube is only one mesh
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "skybox")) {
nd = new Node(Node::SKYBOX);
guessedMeshCnt += 6; // Skybox is a box, with 6 meshes?
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "camera")) {
nd = new Node(Node::CAMERA);
// Setup a temporary name for the camera
aiCamera *cam = new aiCamera();
cam->mName.Set(nd->name);
cameras.push_back(cam);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "light")) {
nd = new Node(Node::LIGHT);
// Setup a temporary name for the light
aiLight *cam = new aiLight();
cam->mName.Set(nd->name);
lights.push_back(cam);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "sphere")) {
nd = new Node(Node::SPHERE);
guessedMeshCnt += 1;
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "animatedMesh")) {
nd = new Node(Node::ANIMMESH);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "empty")) {
nd = new Node(Node::DUMMY);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "terrain")) {
nd = new Node(Node::TERRAIN);
} else if (!ASSIMP_stricmp(nodeTypeAttrib.value(), "billBoard")) {
// We don't support billboards, so ignore them
ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
nd = new Node(Node::DUMMY);
} else {
ASSIMP_LOG_WARN("IRR: Found unknown node: ", nodeTypeAttrib.value());
// If we reached the end of a node, we need to continue processing its parent /* We skip the contents of nodes we don't know.
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) { * We parse the transformation and all animators
if (!curNode) { * and skip the rest.
// currently is no node set. We need to go */
// back in the node hierarchy nd = new Node(Node::DUMMY);
if (!curParent) {
curParent = root;
ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
} else
curParent = curParent->parent;
} else
curNode = nullptr;
} }
// clear all flags
else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
inMaterials = false;
} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
inAnimator = false;
}
break;*/
default: // TODO: consolidate all into one loop
// GCC complains that not all enumeration values are handled for (pugi::xml_node subNode : node.children()) {
break; // Collect node attributes first
if (!ASSIMP_stricmp(subNode.name(), "attributes")) {
ParseNodeAttributes(subNode, nd, batch); // Parse attributes into this node
} else if (!ASSIMP_stricmp(subNode.name(), "animators")) {
// Then parse any animators
// All animators should contain an <attributes> tag
// This is an animation path - add a new animator
// to the list.
ParseAnimators(subNode, nd); // Function modifies nd's animator vector
guessedAnimCnt += 1;
}
// Then parse any materials
// Materials are available to almost all node types
if (nd->type != Node::DUMMY) {
if (!ASSIMP_stricmp(subNode.name(), "materials")) {
// Parse material description directly
// Each material should contain an <attributes> node
// with everything specified
nd->materials.emplace_back();
std::pair<aiMaterial *, unsigned int> &p = nd->materials.back();
p.first = ParseMaterial(subNode, p.second);
guessedMatCnt += 1;
}
}
}
// Then parse any child nodes
// Attach the newly created node to the scene-graph
for (pugi::xml_node child : node.children()) {
if (!ASSIMP_stricmp(child.name(), "node")) { // Is a child node
Node *childNd = ParseNode(child, batch); // Repeat this function for all children
nd->children.push_back(childNd);
};
}
// Return fully specified node
return nd;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file
if (file == nullptr) {
throw DeadlyImportError("Failed to open IRR file ", pFile);
}
// Construct the irrXML parser
XmlParser st;
if (!st.parse(file.get())) {
throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
}
pugi::xml_node documentRoot = st.getRootNode();
// The root node of the scene
Node *root = new Node(Node::DUMMY);
root->parent = nullptr;
root->name = "<IRRSceneRoot>";
// Batch loader used to load external models
BatchLoader batch(pIOHandler);
// batch.SetBasePath(pFile);
cameras.reserve(1); // Probably only one camera in entire scene
lights.reserve(5);
this->guessedAnimCnt = 0;
this->guessedMeshCnt = 0;
this->guessedMatCnt = 0;
// Parse the XML
// Find the scene root from document root.
const pugi::xml_node &sceneRoot = documentRoot.child("irr_scene");
if (!sceneRoot) throw new DeadlyImportError("IRR: <irr_scene> not found in file");
for (pugi::xml_node &child : sceneRoot.children()) {
// XML elements are either nodes, animators, attributes, or materials
if (!ASSIMP_stricmp(child.name(), "node")) {
// Recursive collect subtree children
Node *nd = ParseNode(child, batch);
// Attach to root
root->children.push_back(nd);
}
} }
//}
// Now iterate through all cameras and compute their final (horizontal) FOV // Now iterate through all cameras and compute their final (horizontal) FOV
for (aiCamera *cam : cameras) { for (aiCamera *cam : cameras) {
@ -1337,8 +1329,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Now merge all sub scenes and attach them to the correct // Now merge all sub scenes and attach them to the correct
// attachment points in the scenegraph. // attachment points in the scenegraph.
SceneCombiner::MergeScenes(&pScene, tempScene, attach, SceneCombiner::MergeScenes(&pScene, tempScene, attach,
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
0)); 0));
// If we have no meshes | no materials now set the INCOMPLETE // If we have no meshes | no materials now set the INCOMPLETE

View File

@ -71,13 +71,13 @@ public:
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. * See BaseImporter::CanRead() for details.
*/ */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const override; bool checkSig) const override;
protected: protected:
const aiImporterDesc* GetInfo () const override; const aiImporterDesc *GetInfo() const override;
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override; void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
void SetupProperties(const Importer* pImp) override; void SetupProperties(const Importer *pImp) override;
private: private:
/** Data structure for a scene-graph node animator /** Data structure for a scene-graph node animator
@ -94,18 +94,10 @@ private:
} type; } type;
explicit Animator(AT t = UNKNOWN) explicit Animator(AT t = UNKNOWN) :
: type (t) type(t), speed(ai_real(0.001)), direction(ai_real(0.0), ai_real(1.0), ai_real(0.0)), circleRadius(ai_real(1.0)), tightness(ai_real(0.5)), loop(true), timeForWay(100) {
, speed ( ai_real( 0.001 ) )
, direction ( ai_real( 0.0 ), ai_real( 1.0 ), ai_real( 0.0 ) )
, circleRadius ( ai_real( 1.0) )
, tightness ( ai_real( 0.5 ) )
, loop (true)
, timeForWay (100)
{
} }
// common parameters // common parameters
ai_real speed; ai_real speed;
aiVector3D direction; aiVector3D direction;
@ -128,11 +120,9 @@ private:
/** Data structure for a scene-graph node in an IRR file /** Data structure for a scene-graph node in an IRR file
*/ */
struct Node struct Node {
{
// Type of the node // Type of the node
enum ET enum ET {
{
LIGHT, LIGHT,
CUBE, CUBE,
MESH, MESH,
@ -144,21 +134,20 @@ private:
ANIMMESH ANIMMESH
} type; } type;
explicit Node(ET t) explicit Node(ET t) :
: type (t) type(t), scaling(1.0, 1.0, 1.0) // assume uniform scaling by default
, scaling (1.0,1.0,1.0) // assume uniform scaling by default ,
, parent() parent(),
, framesPerSecond (0.0) framesPerSecond(0.0),
, id() id(),
, sphereRadius (1.0) sphereRadius(1.0),
, spherePolyCountX (100) spherePolyCountX(100),
, spherePolyCountY (100) spherePolyCountY(100) {
{
// Generate a default name for the node // Generate a default name for the node
char buffer[128]; char buffer[128];
static int cnt; static int cnt;
ai_snprintf(buffer, 128, "IrrNode_%i",cnt++); ai_snprintf(buffer, 128, "IrrNode_%i", cnt++);
name = std::string(buffer); name = std::string(buffer);
// reserve space for up to 5 materials // reserve space for up to 5 materials
@ -175,10 +164,10 @@ private:
std::string name; std::string name;
// List of all child nodes // List of all child nodes
std::vector<Node*> children; std::vector<Node *> children;
// Parent node // Parent node
Node* parent; Node *parent;
// Animated meshes: frames per second // Animated meshes: frames per second
// 0.f if not specified // 0.f if not specified
@ -190,13 +179,13 @@ private:
// Meshes: List of materials to be assigned // Meshes: List of materials to be assigned
// along with their corresponding material flags // along with their corresponding material flags
std::vector< std::pair<aiMaterial*, unsigned int> > materials; std::vector<std::pair<aiMaterial *, unsigned int>> materials;
// Spheres: radius of the sphere to be generates // Spheres: radius of the sphere to be generates
ai_real sphereRadius; ai_real sphereRadius;
// Spheres: Number of polygons in the x,y direction // Spheres: Number of polygons in the x,y direction
unsigned int spherePolyCountX,spherePolyCountY; unsigned int spherePolyCountX, spherePolyCountY;
// List of all animators assigned to the node // List of all animators assigned to the node
std::list<Animator> animators; std::list<Animator> animators;
@ -204,8 +193,7 @@ private:
/** Data structure for a vertex in an IRR skybox /** Data structure for a vertex in an IRR skybox
*/ */
struct SkyboxVertex struct SkyboxVertex {
{
SkyboxVertex() = default; SkyboxVertex() = default;
//! Construction from single vertex components //! Construction from single vertex components
@ -213,31 +201,46 @@ private:
ai_real nx, ai_real ny, ai_real nz, ai_real nx, ai_real ny, ai_real nz,
ai_real uvx, ai_real uvy) ai_real uvx, ai_real uvy)
: position (px,py,pz) :
, normal (nx,ny,nz) position(px, py, pz), normal(nx, ny, nz), uv(uvx, uvy, 0.0) {}
, uv (uvx,uvy,0.0)
{}
aiVector3D position, normal, uv; aiVector3D position, normal, uv;
}; };
// -------------------------------------------------------------------
// Parse <node> tag from XML file and extract child node
// @param node XML node
// @param guessedMeshesContained number of extra guessed meshes
IRRImporter::Node *ParseNode(pugi::xml_node &node, BatchLoader& batch);
// -------------------------------------------------------------------
// Parse <attributes> tags within <node> tags and apply to scene node
// @param attributeNode XML child node
// @param nd Attributed scene node
void ParseNodeAttributes(pugi::xml_node &attributeNode, IRRImporter::Node *nd, BatchLoader& batch);
// -------------------------------------------------------------------
// Parse an <animator> node and attach an animator to a node
// @param animatorNode XML animator node
// @param nd Animated scene node
void ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/// Fill the scene-graph recursively /// Fill the scene-graph recursively
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
BatchLoader& batch, BatchLoader &batch,
std::vector<aiMesh*>& meshes, std::vector<aiMesh *> &meshes,
std::vector<aiNodeAnim*>& anims, std::vector<aiNodeAnim *> &anims,
std::vector<AttachmentInfo>& attach, std::vector<AttachmentInfo> &attach,
std::vector<aiMaterial*>& materials, std::vector<aiMaterial *> &materials,
unsigned int& defaultMatIdx); unsigned int &defaultMatIdx);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/// Generate a mesh that consists of just a single quad /// Generate a mesh that consists of just a single quad
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1, aiMesh *BuildSingleQuadMesh(const SkyboxVertex &v1,
const SkyboxVertex& v2, const SkyboxVertex &v2,
const SkyboxVertex& v3, const SkyboxVertex &v3,
const SkyboxVertex& v4); const SkyboxVertex &v4);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/// Build a sky-box /// Build a sky-box
@ -245,8 +248,8 @@ private:
/// @param meshes Receives 6 output meshes /// @param meshes Receives 6 output meshes
/// @param materials The last 6 materials are assigned to the newly /// @param materials The last 6 materials are assigned to the newly
/// created meshes. The names of the materials are adjusted. /// created meshes. The names of the materials are adjusted.
void BuildSkybox(std::vector<aiMesh*>& meshes, void BuildSkybox(std::vector<aiMesh *> &meshes,
std::vector<aiMaterial*> materials); std::vector<aiMaterial *> materials);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Copy a material for a mesh to the output material list /** Copy a material for a mesh to the output material list
@ -256,10 +259,10 @@ private:
* @param defMatIdx Default material index - UINT_MAX if not present * @param defMatIdx Default material index - UINT_MAX if not present
* @param mesh Mesh to work on * @param mesh Mesh to work on
*/ */
void CopyMaterial(std::vector<aiMaterial*>& materials, void CopyMaterial(std::vector<aiMaterial *> &materials,
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials, std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
unsigned int& defMatIdx, unsigned int &defMatIdx,
aiMesh* mesh); aiMesh *mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Compute animations for a specific node /** Compute animations for a specific node
@ -267,8 +270,8 @@ private:
* @param root Node to be processed * @param root Node to be processed
* @param anims The list of output animations * @param anims The list of output animations
*/ */
void ComputeAnimations(Node* root, aiNode* real, void ComputeAnimations(Node *root, aiNode *real,
std::vector<aiNodeAnim*>& anims); std::vector<aiNodeAnim *> &anims);
private: private:
/// Configuration option: desired output FPS /// Configuration option: desired output FPS
@ -276,6 +279,12 @@ private:
/// Configuration option: speed flag was set? /// Configuration option: speed flag was set?
bool configSpeedFlag; bool configSpeedFlag;
std::vector<aiCamera*> cameras;
std::vector<aiLight*> lights;
unsigned int guessedMeshCnt;
unsigned int guessedMatCnt;
unsigned int guessedAnimCnt;
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -71,11 +71,7 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
IRRMeshImporter::IRRMeshImporter() : IRRMeshImporter::IRRMeshImporter() = default;
BaseImporter(),
IrrlichtBase() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
@ -125,7 +121,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// Construct the irrXML parser // Construct the irrXML parser
XmlParser parser; XmlParser parser;
if (!parser.parse( file.get() )) { if (!parser.parse(file.get())) {
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile); throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
} }
XmlNode root = parser.getRootNode(); XmlNode root = parser.getRootNode();
@ -137,6 +133,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
meshes.reserve(5); meshes.reserve(5);
// temporary data - current mesh buffer // temporary data - current mesh buffer
// TODO move all these to inside loop
aiMaterial *curMat = nullptr; aiMaterial *curMat = nullptr;
aiMesh *curMesh = nullptr; aiMesh *curMesh = nullptr;
unsigned int curMatFlags = 0; unsigned int curMatFlags = 0;
@ -146,23 +143,28 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
std::vector<aiVector3D> curUVs, curUV2s; std::vector<aiVector3D> curUVs, curUV2s;
// some temporary variables // some temporary variables
int textMeaning = 0; // textMeaning is a 15 year old variable, that could've been an enum
int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents // int textMeaning = 0; // 0=none? 1=vertices 2=indices
// int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
bool useColors = false; bool useColors = false;
/*
** irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
** Each <buffer> contains <material>, <vertices>, and <indices>
** <material> tags here directly owns the material data specs
** <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
** <boundingbox> is ignored, I think assimp recalculates those?
*/
// Parse the XML file // Parse the XML file
for (pugi::xml_node child : root.children()) { pugi::xml_node const &meshNode = root.child("mesh");
if (child.type() == pugi::node_element) { for (pugi::xml_node bufferNode : meshNode.children()) {
if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) { if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
// end of previous buffer. A material and a mesh should be there // Might be a useless warning
if (!curMat || !curMesh) { ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); continue;
releaseMaterial(&curMat);
releaseMesh(&curMesh);
} else {
materials.push_back(curMat);
meshes.push_back(curMesh);
} }
curMat = nullptr; curMat = nullptr;
curMesh = nullptr; curMesh = nullptr;
@ -173,42 +175,47 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
curUVs.clear(); curUVs.clear();
curTangents.clear(); curTangents.clear();
curBitangents.clear(); curBitangents.clear();
}
if (!ASSIMP_stricmp(child.name(), "material")) { // TODO ensure all three nodes are present and populated
if (curMat) { // before allocating everything
// Get first material node
pugi::xml_node materialNode = bufferNode.child("material");
if (materialNode) {
curMat = ParseMaterial(materialNode, curMatFlags);
// Warn if there's more materials
if (materialNode.next_sibling("material")) {
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please"); ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
releaseMaterial(&curMat);
} }
curMat = ParseMaterial(curMatFlags); } else {
} ASSIMP_LOG_ERROR("IRRMESH: Buffer must contain one material");
/* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
pugi::xml_attribute attr = child.attribute("vertexCount");
int num = attr.as_int();
//int num = reader->getAttributeValueAsInt("vertexCount");
if (!num) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
releaseMaterial(&curMat);
releaseMesh(&curMesh);
textMeaning = 0;
continue; continue;
} }
curVertices.reserve(num); // Get first vertices node
curNormals.reserve(num); pugi::xml_node verticesNode = bufferNode.child("vertices");
curColors.reserve(num); if (verticesNode) {
curUVs.reserve(num); pugi::xml_attribute vertexCountAttrib = verticesNode.attribute("vertexCount");
int vertexCount = vertexCountAttrib.as_int();
if (vertexCount == 0) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
releaseMaterial(&curMat);
// releaseMesh(&curMesh);
continue; // Bail out early
};
curVertices.reserve(vertexCount);
curNormals.reserve(vertexCount);
curColors.reserve(vertexCount);
curUVs.reserve(vertexCount);
VertexFormat vertexFormat;
// Determine the file format // Determine the file format
//const char *t = reader->getAttributeValueSafe("type"); pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
pugi::xml_attribute t = child.attribute("type"); if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
if (!ASSIMP_stricmp("2tcoords", t.name())) { curUV2s.reserve(vertexCount);
curUV2s.reserve(num); vertexFormat = VertexFormat::t2coord;
vertexFormat = 1;
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) { if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
// ********************************************************* // *********************************************************
// We have a second texture! So use this UV channel // We have a second texture! So use this UV channel
@ -227,29 +234,38 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1)); mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
} }
} }
} else if (!ASSIMP_stricmp("tangents", t.name())) { } else if (!ASSIMP_stricmp("tangents", typeAttrib.value())) {
curTangents.reserve(num); curTangents.reserve(vertexCount);
curBitangents.reserve(num); curBitangents.reserve(vertexCount);
vertexFormat = 2; vertexFormat = VertexFormat::tangent;
} else if (ASSIMP_stricmp("standard", t.name())) { } else if (!ASSIMP_stricmp("standard", typeAttrib.value())) {
vertexFormat = VertexFormat::standard;
} else {
// Unsupported format, discard whole buffer/mesh
// Assuming we have a correct material, then release it
// We don't have a correct mesh for sure here
releaseMaterial(&curMat); releaseMaterial(&curMat);
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format"); ASSIMP_LOG_ERROR("IRRMESH: Unknown vertex format");
} else continue; // Skip rest of buffer
vertexFormat = 0; };
textMeaning = 1;
} else if (!ASSIMP_stricmp(child.name(), "indices")) { // We know what format buffer is, collect numbers
if (curVertices.empty() && curMat) { ParseBufferVertices(verticesNode.text().get(), vertexFormat,
releaseMaterial(&curMat); curVertices, curNormals,
throw DeadlyImportError("IRRMESH: indices must come after vertices"); curTangents, curBitangents,
curUVs, curUV2s, curColors, useColors);
} }
textMeaning = 2; // Get indices
// At this point we have some vertices and a valid material
// Collect indices and create aiMesh at the same time
pugi::xml_node indicesNode = bufferNode.child("indices");
if (indicesNode) {
// start a new mesh // start a new mesh
curMesh = new aiMesh(); curMesh = new aiMesh();
// allocate storage for all faces // allocate storage for all faces
pugi::xml_attribute attr = child.attribute("indexCount"); pugi::xml_attribute attr = indicesNode.attribute("indexCount");
curMesh->mNumVertices = attr.as_int(); curMesh->mNumVertices = attr.as_int();
if (!curMesh->mNumVertices) { if (!curMesh->mNumVertices) {
// This is possible ... remove the mesh from the list and skip further reading // This is possible ... remove the mesh from the list and skip further reading
@ -260,9 +276,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// material - away // material - away
releaseMaterial(&curMat); releaseMaterial(&curMat);
continue; // Go to next buffer
textMeaning = 0;
continue;
} }
if (curMesh->mNumVertices % 3) { if (curMesh->mNumVertices % 3) {
@ -297,107 +311,6 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
if (curUV2s.size() == curVertices.size()) { if (curUV2s.size() == curVertices.size()) {
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
} }
}
//break;
//case EXN_TEXT: {
const char *sz = child.child_value();
if (textMeaning == 1) {
textMeaning = 0;
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
aiVector3D temp;
aiColor4D c;
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
curVertices.push_back(temp);
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
curNormals.push_back(temp);
// read the vertex colors
uint32_t clr = strtoul16(sz, &sz);
ColorFromARGBPacked(clr, c);
if (!curColors.empty() && c != *(curColors.end() - 1))
useColors = true;
curColors.push_back(c);
SkipSpaces(&sz);
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
curUVs.push_back(temp);
// read the (optional) second UV coordinate set
if (vertexFormat == 1) {
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
temp.y = 1.f - temp.y; // DX to OGL
curUV2s.push_back(temp);
}
// read optional tangent and bitangent vectors
else if (vertexFormat == 2) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
curTangents.push_back(temp);
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
curBitangents.push_back(temp);
}
}
/* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
elements are ignored.
*/
while (SkipLine(&sz));
} else if (textMeaning == 2) {
textMeaning = 0;
// read indices // read indices
aiFace *curFace = curMesh->mFaces; aiFace *curFace = curMesh->mFaces;
@ -413,24 +326,33 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
unsigned int curIdx = 0; unsigned int curIdx = 0;
unsigned int total = 0; unsigned int total = 0;
// NOTE this might explode for UTF-16 and wchars
const char *sz = indicesNode.text().get();
// For each index loop over aiMesh faces
while (SkipSpacesAndLineEnd(&sz)) { while (SkipSpacesAndLineEnd(&sz)) {
if (curFace >= faceEnd) { if (curFace >= faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Too many indices"); ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break; break;
} }
// if new face
if (!curIdx) { if (!curIdx) {
curFace->mNumIndices = 3; curFace->mNumIndices = 3;
curFace->mIndices = new unsigned int[3]; curFace->mIndices = new unsigned int[3];
} }
// Read index base 10
// function advances the pointer
unsigned int idx = strtoul10(sz, &sz); unsigned int idx = strtoul10(sz, &sz);
if (idx >= curVertices.size()) { if (idx >= curVertices.size()) {
ASSIMP_LOG_ERROR("IRRMESH: Index out of range"); ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0; idx = 0;
} }
// make up our own indices?
curFace->mIndices[curIdx] = total++; curFace->mIndices[curIdx] = total++;
// Copy over data to aiMesh
*pcV++ = curVertices[idx]; *pcV++ = curVertices[idx];
if (pcN) *pcN++ = curNormals[idx]; if (pcN) *pcN++ = curNormals[idx];
if (pcT) *pcT++ = curTangents[idx]; if (pcT) *pcT++ = curTangents[idx];
@ -439,14 +361,16 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
if (pcT0) *pcT0++ = curUVs[idx]; if (pcT0) *pcT0++ = curUVs[idx];
if (pcT1) *pcT1++ = curUV2s[idx]; if (pcT1) *pcT1++ = curUV2s[idx];
// start new face
if (++curIdx == 3) { if (++curIdx == 3) {
++curFace; ++curFace;
curIdx = 0; curIdx = 0;
} }
} }
// We should be at the end of mFaces
if (curFace != faceEnd) if (curFace != faceEnd)
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices"); ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
}
// Finish processing the mesh - do some small material workarounds // Finish processing the mesh - do some small material workarounds
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) { if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
@ -455,12 +379,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
aiMaterial *mat = (aiMaterial *)curMat; aiMaterial *mat = (aiMaterial *)curMat;
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY); mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
} }
} // textMeaning = 2;
}
}
// End of the last buffer. A material and a mesh should be there // end of previous buffer. A material and a mesh should be there
if (curMat || curMesh) {
if (!curMat || !curMesh) { if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial(&curMat); releaseMaterial(&curMat);
@ -471,7 +392,8 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
} }
} }
if (materials.empty()) { // If one is empty then so is the other
if (materials.empty() || meshes.empty()) {
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file"); throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
} }
@ -496,7 +418,105 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mRootNode->mMeshes[i] = i; pScene->mRootNode->mMeshes[i] = i;
};
}
void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors) {
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
aiVector3D temp;
aiColor4D c;
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
vertices.push_back(temp);
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
normals.push_back(temp);
// read the vertex colors
uint32_t clr = strtoul16(sz, &sz);
ColorFromARGBPacked(clr, c);
// If we're pushing more than one distinct color
if (!colors.empty() && c != *(colors.end() - 1))
useColors = true;
colors.push_back(c);
SkipSpaces(&sz);
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
UVs.push_back(temp);
// NOTE these correspond to specific S3DVertex* structs in irr sourcecode
// 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);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)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);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
tangents.push_back(temp);
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
bitangents.push_back(temp);
}
} while (SkipLine(&sz));
/* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
elements are ignored.
*/
} }
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER #endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

View File

@ -85,6 +85,19 @@ protected:
*/ */
void InternReadFile(const std::string &pFile, aiScene *pScene, void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler) override; IOSystem *pIOHandler) override;
private:
enum class VertexFormat {
standard = 0, // "standard" - also noted as 'normal' format elsewhere
t2coord = 1, // "2tcoord" - standard + 2 UV maps
tangent = 2, // "tangents" - standard + tangents and bitangents
};
void ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors);
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -43,19 +43,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Shared utilities for the IRR and IRRMESH loaders * @brief Shared utilities for the IRR and IRRMESH loaders
*/ */
//This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted. // This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER)) #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
#include "IRRShared.h" #include "IRRShared.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/DefaultLogger.hpp>
using namespace Assimp; using namespace Assimp;
// Transformation matrix to convert from Assimp to IRR space // Transformation matrix to convert from Assimp to IRR space
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 ( const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
@ -63,34 +63,34 @@ const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a property in hexadecimal format (i.e. ffffffff) // read a property in hexadecimal format (i.e. ffffffff)
void IrrlichtBase::ReadHexProperty(HexProperty &out ) { void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : hexnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string( attrib.value() ); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(),"value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the hexadecimal value // parse the hexadecimal value
out.value = strtoul16(attrib.name()); out.value = strtoul16(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a decimal property // read a decimal property
void IrrlichtBase::ReadIntProperty(IntProperty & out) { void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : intnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.value(),"value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the int value // parse the int value
out.value = strtol10(attrib.name()); out.value = strtol10(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a string property // read a string property
void IrrlichtBase::ReadStringProperty( StringProperty& out) { void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : stringnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
@ -102,9 +102,9 @@ void IrrlichtBase::ReadStringProperty( StringProperty& out) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a boolean property // read a boolean property
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) { void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : boolnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")){ if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// true or false, case insensitive // true or false, case insensitive
@ -115,8 +115,8 @@ void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a float property // read a float property
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) { void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : floatnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
@ -128,8 +128,8 @@ void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a vector property // read a vector property
void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) { void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : vectornode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
@ -137,28 +137,28 @@ void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
const char *ptr = attrib.value(); const char *ptr = attrib.value();
SkipSpaces(&ptr); SkipSpaces(&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) { if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else { } else {
SkipSpaces(ptr + 1, &ptr); SkipSpaces(ptr + 1, &ptr);
} }
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) { if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else { } else {
SkipSpaces(ptr + 1, &ptr); SkipSpaces(ptr + 1, &ptr);
} }
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a string to a proper aiMappingMode // Convert a string to a proper aiMappingMode
int ConvertMappingMode(const std::string& mode) { int ConvertMappingMode(const std::string &mode) {
if (mode == "texture_clamp_repeat") { if (mode == "texture_clamp_repeat") {
return aiTextureMapMode_Wrap; return aiTextureMapMode_Wrap;
} else if (mode == "texture_clamp_mirror") { } else if (mode == "texture_clamp_mirror") {
@ -170,8 +170,8 @@ int ConvertMappingMode(const std::string& mode) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Parse a material from the XML file // Parse a material from the XML file
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) { aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
aiMaterial* mat = new aiMaterial(); aiMaterial *mat = new aiMaterial();
aiColor4D clr; aiColor4D clr;
aiString s; aiString s;
@ -179,10 +179,10 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
int cnt = 0; // number of used texture channels int cnt = 0; // number of used texture channels
unsigned int nd = 0; unsigned int nd = 0;
for (pugi::xml_node child : mNode->children()) { for (pugi::xml_node child : materialNode.children()) {
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
HexProperty prop; HexProperty prop;
ReadHexProperty(prop); ReadHexProperty(prop, child);
if (prop.name == "Diffuse") { if (prop.name == "Diffuse") {
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
@ -206,13 +206,13 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
#endif #endif
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties } else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop, child);
if (prop.name == "Shininess") { if (prop.name == "Shininess") {
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS); mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
} }
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties } else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop, child);
if (prop.name == "Wireframe") { if (prop.name == "Wireframe") {
int val = (prop.value ? true : false); int val = (prop.value ? true : false);
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME); mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
@ -226,7 +226,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
} else if (!ASSIMP_stricmp(child.name(), "texture") || } else if (!ASSIMP_stricmp(child.name(), "texture") ||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop, child);
if (prop.value.length()) { if (prop.value.length()) {
// material type (shader) // material type (shader)
if (prop.name == "Type") { if (prop.name == "Type") {
@ -337,7 +337,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
} }
} }
} }
//break; // break;
/*case EXN_ELEMENT_END: /*case EXN_ELEMENT_END:
// Assume there are no further nested nodes in <material> elements // Assume there are no further nested nodes in <material> elements
@ -379,7 +379,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
} }
}*/ }*/
} }
ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete"); //ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
return mat; return mat;
} }

View File

@ -58,14 +58,11 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
*/ */
class IrrlichtBase { class IrrlichtBase {
protected: protected:
IrrlichtBase() : IrrlichtBase() {
mNode(nullptr) {
// empty // empty
} }
~IrrlichtBase() { ~IrrlichtBase() = default;
// empty
}
/** @brief Data structure for a simple name-value property /** @brief Data structure for a simple name-value property
*/ */
@ -84,25 +81,25 @@ protected:
/// XML reader instance /// XML reader instance
XmlParser mParser; XmlParser mParser;
pugi::xml_node *mNode;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Parse a material description from the XML /** Parse a material description from the XML
* @return The created material * @return The created material
* @param matFlags Receives AI_IRRMESH_MAT_XX flags * @param matFlags Receives AI_IRRMESH_MAT_XX flags
*/ */
aiMaterial *ParseMaterial(unsigned int &matFlags); aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Read a property of the specified type from the current XML element. /** Read a property of the specified type from the current XML element.
* @param out Receives output data * @param out Receives output data
* @param node XML attribute element containing data
*/ */
void ReadHexProperty(HexProperty &out); void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
void ReadStringProperty(StringProperty &out); void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
void ReadBoolProperty(BoolProperty &out); void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
void ReadFloatProperty(FloatProperty &out); void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
void ReadVectorProperty(VectorProperty &out); void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
void ReadIntProperty(IntProperty &out); void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -162,8 +162,11 @@ void AnimResolver::UpdateAnimRangeSetup() {
const double my_last = (*it).keys.back().time; const double my_last = (*it).keys.back().time;
const double delta = my_last - my_first; const double delta = my_last - my_first;
const size_t old_size = (*it).keys.size(); if (delta == 0.0) {
continue;
}
const size_t old_size = (*it).keys.size();
const float value_delta = (*it).keys.back().value - (*it).keys.front().value; const float value_delta = (*it).keys.back().value - (*it).keys.front().value;
// NOTE: We won't handle reset, linear and constant here. // NOTE: We won't handle reset, linear and constant here.
@ -176,8 +179,7 @@ void AnimResolver::UpdateAnimRangeSetup() {
case LWO::PrePostBehaviour_Oscillate: { case LWO::PrePostBehaviour_Oscillate: {
const double start_time = delta - std::fmod(my_first - first, delta); const double start_time = delta - std::fmod(my_first - first, delta);
std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(), std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(),
[start_time](double t) { return start_time > t; }), [start_time](double t) { return start_time > t; }), m;
m;
size_t ofs = 0; size_t ofs = 0;
if (n != (*it).keys.end()) { if (n != (*it).keys.end()) {

View File

@ -65,7 +65,6 @@ void LWOImporter::LoadLWOBFile()
if (mFileBuffer + head.length > end) if (mFileBuffer + head.length > end)
{ {
throw DeadlyImportError("LWOB: Invalid chunk length"); throw DeadlyImportError("LWOB: Invalid chunk length");
break;
} }
uint8_t* const next = mFileBuffer+head.length; uint8_t* const next = mFileBuffer+head.length;
switch (head.type) switch (head.type)

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -51,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetLib/LWO/LWOLoader.h" #include "AssetLib/LWO/LWOLoader.h"
#include "PostProcessing/ConvertToLHProcess.h" #include "PostProcessing/ConvertToLHProcess.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
#include "Geometry/GeometryUtils.h"
#include <assimp/ByteSwapper.h> #include <assimp/ByteSwapper.h>
#include <assimp/SGSpatialSort.h> #include <assimp/SGSpatialSort.h>
@ -178,7 +177,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
mLayers->push_back(Layer()); mLayers->push_back(Layer());
mCurLayer = &mLayers->back(); mCurLayer = &mLayers->back();
mCurLayer->mName = "<LWODefault>"; mCurLayer->mName = "<LWODefault>";
mCurLayer->mIndex = (uint16_t) -1; mCurLayer->mIndex = 1;
// old lightwave file format (prior to v6) // old lightwave file format (prior to v6)
mIsLWO2 = false; mIsLWO2 = false;
@ -398,14 +397,6 @@ void LWOImporter::InternReadFile(const std::string &pFile,
pvVC[w]++; pvVC[w]++;
} }
#if 0
// process vertex weights. We can't properly reconstruct the whole skeleton for now,
// but we can create dummy bones for all weight channels which we have.
for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
{
}
#endif
face.mIndices[q] = vert; face.mIndices[q] = vert;
} }
pf->mIndices = face.mIndices; pf->mIndices = face.mIndices;
@ -429,7 +420,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
// Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart); unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
if (layer.mName != "<LWODefault>" || num > 0) { if (layer.mName != "<LWODefault>" || num > 0) {
aiNode *pcNode = new aiNode(); std::unique_ptr<aiNode> pcNode(new aiNode());
pcNode->mName.Set(layer.mName); pcNode->mName.Set(layer.mName);
pcNode->mParent = (aiNode *)&layer; pcNode->mParent = (aiNode *)&layer;
pcNode->mNumMeshes = num; pcNode->mNumMeshes = num;
@ -439,7 +430,8 @@ void LWOImporter::InternReadFile(const std::string &pFile,
for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p) for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p)
pcNode->mMeshes[p] = p + meshStart; pcNode->mMeshes[p] = p + meshStart;
} }
apcNodes[layer.mIndex] = pcNode; ASSIMP_LOG_DEBUG("insert apcNode for layer ", layer.mIndex, " \"", layer.mName, "\"");
apcNodes[layer.mIndex] = pcNode.release();
} }
} }
@ -535,7 +527,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
continue; continue;
vNormals += v; vNormals += v;
} }
mesh->mNormals[idx] = vNormals.Normalize();
} }
} }
} }
@ -556,7 +547,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
const aiVector3D &v = faceNormals[*a]; const aiVector3D &v = faceNormals[*a];
vNormals += v; vNormals += v;
} }
vNormals.Normalize();
for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) { for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
mesh->mNormals[*a] = vNormals; mesh->mNormals[*a] = vNormals;
vertexDone[*a] = true; vertexDone[*a] = true;
@ -564,6 +554,7 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
} }
} }
} }
GeometryUtils::normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -572,7 +563,13 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
aiNode *root = mScene->mRootNode = new aiNode(); aiNode *root = mScene->mRootNode = new aiNode();
root->mName.Set("<LWORoot>"); root->mName.Set("<LWORoot>");
ASSIMP_LOG_DEBUG("apcNodes initial size: ", apcNodes.size());
if (!apcNodes.empty()) {
ASSIMP_LOG_DEBUG("first apcNode is: ", apcNodes.begin()->first, " \"", apcNodes.begin()->second->mName.C_Str(), "\"");
}
//Set parent of all children, inserting pivots //Set parent of all children, inserting pivots
{
std::map<uint16_t, aiNode *> mapPivot; std::map<uint16_t, aiNode *> mapPivot;
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
@ -581,9 +578,9 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
uint16_t parentIndex = nodeLayer->mParent; uint16_t parentIndex = nodeLayer->mParent;
//Create pivot node, store it into the pivot map, and set the parent as the pivot //Create pivot node, store it into the pivot map, and set the parent as the pivot
aiNode *pivotNode = new aiNode(); std::unique_ptr<aiNode> pivotNode(new aiNode());
pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data)); pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
itapcNodes->second->mParent = pivotNode; itapcNodes->second->mParent = pivotNode.get();
//Look for the parent node to attach the pivot to //Look for the parent node to attach the pivot to
if (apcNodes.find(parentIndex) != apcNodes.end()) { if (apcNodes.find(parentIndex) != apcNodes.end()) {
@ -600,12 +597,30 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
mapPivot[-(itapcNodes->first + 2)] = pivotNode; uint16_t pivotNodeId = static_cast<uint16_t>(-(itapcNodes->first + 2));
ASSIMP_LOG_DEBUG("insert pivot node: ", pivotNodeId);
auto oldNodeIt = mapPivot.find(pivotNodeId);
if (oldNodeIt != mapPivot.end()) {
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in pivot map ", pivotNodeId, " \"", pivotNode->mName.C_Str(), "\"");
} else {
mapPivot.emplace(pivotNodeId, pivotNode.release());
}
} }
ASSIMP_LOG_DEBUG("pivot nodes: ", mapPivot.size());
//Merge pivot map into node map //Merge pivot map into node map
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end();) {
apcNodes[itMapPivot->first] = itMapPivot->second; uint16_t pivotNodeId = itMapPivot->first;
auto oldApcNodeIt = apcNodes.find(pivotNodeId);
if (oldApcNodeIt != apcNodes.end()) {
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in apc nodes ", pivotNodeId, " \"", itMapPivot->second->mName.C_Str(), "\"");
} else {
apcNodes.emplace(pivotNodeId, itMapPivot->second);
}
itMapPivot->second = nullptr;
itMapPivot = mapPivot.erase(itMapPivot);
}
ASSIMP_LOG_DEBUG("total nodes: ", apcNodes.size());
} }
//Set children of all parents //Set children of all parents
@ -627,8 +642,15 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
} }
} }
if (!mScene->mRootNode->mNumChildren) if (!mScene->mRootNode->mNumChildren) {
ASSIMP_LOG_DEBUG("All apcNodes:");
for (auto nodeIt = apcNodes.begin(); nodeIt != apcNodes.end(); ) {
ASSIMP_LOG_DEBUG("Node ", nodeIt->first, " \"", nodeIt->second->mName.C_Str(), "\"");
nodeIt->second = nullptr;
nodeIt = apcNodes.erase(nodeIt);
}
throw DeadlyImportError("LWO: Unable to build a valid node graph"); throw DeadlyImportError("LWO: Unable to build a valid node graph");
}
// Remove a single root node with no meshes assigned to it ... // Remove a single root node with no meshes assigned to it ...
if (1 == mScene->mRootNode->mNumChildren) { if (1 == mScene->mRootNode->mNumChildren) {
@ -1462,7 +1484,6 @@ void LWOImporter::LoadLWO2File() {
if (mFileBuffer + head.length > end) { if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO2: Chunk length points behind the file"); throw DeadlyImportError("LWO2: Chunk length points behind the file");
break;
} }
uint8_t *const next = mFileBuffer + head.length; uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset; mFileBuffer += bufOffset;

View File

@ -345,7 +345,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
// (the diffuse value is just a scaling factor) // (the diffuse value is just a scaling factor)
// If a diffuse texture is set, we set this value to 1.0 // If a diffuse texture is set, we set this value to 1.0
clr = (b && false ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor); clr = (b ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
clr.r *= surf.mDiffuseValue; clr.r *= surf.mDiffuseValue;
clr.g *= surf.mDiffuseValue; clr.g *= surf.mDiffuseValue;
clr.b *= surf.mDiffuseValue; clr.b *= surf.mDiffuseValue;

View File

@ -632,8 +632,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
nodes.push_back(d); nodes.push_back(d);
} }
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'"); ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'");
} } else {
// important: index of channel // important: index of channel
nodes.back().channels.emplace_back(); nodes.back().channels.emplace_back();
LWO::Envelope &env = nodes.back().channels.back(); LWO::Envelope &env = nodes.back().channels.back();
@ -643,7 +642,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// currently we can just interpret the standard channels 0...9 // currently we can just interpret the standard channels 0...9
// (hack) assume that index-i yields the binary channel type from LWO // (hack) assume that index-i yields the binary channel type from LWO
env.type = (LWO::EnvelopeType)(env.index + 1); env.type = (LWO::EnvelopeType)(env.index + 1);
}
} }
// 'Envelope': a single animation channel // 'Envelope': a single animation channel
else if ((*it).tokens[0] == "Envelope") { else if ((*it).tokens[0] == "Envelope") {

View File

@ -65,7 +65,7 @@ class M3DImporter : public BaseImporter {
public: public:
/// \brief Default constructor /// \brief Default constructor
M3DImporter(); M3DImporter();
~M3DImporter() override {} ~M3DImporter() override = default;
/// \brief Returns whether the class can handle the format of the given file. /// \brief Returns whether the class can handle the format of the given file.
/// \remark See BaseImporter::CanRead() for details. /// \remark See BaseImporter::CanRead() for details.

View File

@ -39,8 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #if !defined ASSIMP_BUILD_NO_M3D_IMPORTER || !(defined ASSIMP_BUILD_NO_EXPORT || defined ASSIMP_BUILD_NO_M3D_EXPORTER)
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
#include "M3DWrapper.h" #include "M3DWrapper.h"
@ -149,4 +148,3 @@ void M3DWrapper::ClearSave() {
} // namespace Assimp } // namespace Assimp
#endif #endif
#endif

View File

@ -47,8 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_M3DWRAPPER_H_INC #ifndef AI_M3DWRAPPER_H_INC
#define AI_M3DWRAPPER_H_INC #define AI_M3DWRAPPER_H_INC
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #if !defined ASSIMP_BUILD_NO_M3D_IMPORTER || !(defined ASSIMP_BUILD_NO_EXPORT || defined ASSIMP_BUILD_NO_M3D_EXPORTER)
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -126,7 +125,6 @@ inline m3d_t *M3DWrapper::M3D() const {
} // namespace Assimp } // namespace Assimp
#endif
#endif // ASSIMP_BUILD_NO_M3D_IMPORTER #endif // ASSIMP_BUILD_NO_M3D_IMPORTER
#endif // AI_M3DWRAPPER_H_INC #endif // AI_M3DWRAPPER_H_INC

View File

@ -138,18 +138,31 @@ bool MD5Parser::ParseSection(Section &out) {
char *sz = buffer; char *sz = buffer;
while (!IsSpaceOrNewLine(*buffer)) { while (!IsSpaceOrNewLine(*buffer)) {
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
} }
out.mName = std::string(sz, (uintptr_t)(buffer - sz)); out.mName = std::string(sz, (uintptr_t)(buffer - sz));
SkipSpaces(); while (IsSpace(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
bool running = true; bool running = true;
while (running) { while (running) {
if ('{' == *buffer) { if ('{' == *buffer) {
// it is a normal section so read all lines // it is a normal section so read all lines
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
bool run = true; bool run = true;
while (run) { while (run) {
if (!SkipSpacesAndLineEnd()) { while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
if ('\0' == *buffer) {
return false; // seems this was the last section return false; // seems this was the last section
} }
if ('}' == *buffer) { if ('}' == *buffer) {
@ -164,25 +177,39 @@ bool MD5Parser::ParseSection(Section &out) {
elem.szStart = buffer; elem.szStart = buffer;
// terminate the line with zero // terminate the line with zero
while (!IsLineEnd(*buffer)) while (!IsLineEnd(*buffer)) {
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
}
if (*buffer) { if (*buffer) {
++lineNumber; ++lineNumber;
*buffer++ = '\0'; *buffer++ = '\0';
if (buffer == bufferEnd)
return false;
} }
} }
break; break;
} else if (!IsSpaceOrNewLine(*buffer)) { } else if (!IsSpaceOrNewLine(*buffer)) {
// it is an element at global scope. Parse its value and go on // it is an element at global scope. Parse its value and go on
sz = buffer; sz = buffer;
while (!IsSpaceOrNewLine(*buffer++)) while (!IsSpaceOrNewLine(*buffer++)) {
; if (buffer == bufferEnd)
return false;
}
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz)); out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
continue; continue;
} }
break; break;
} }
return SkipSpacesAndLineEnd(); if (buffer == bufferEnd)
return false;
while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
return '\0' != *buffer;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -229,14 +256,19 @@ bool MD5Parser::ParseSection(Section &out) {
// parse a string, enclosed in quotation marks // parse a string, enclosed in quotation marks
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \ #define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
while ('\"' != *sz) \ out.length = 0; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \ ++sz; \
if ('\0' != *sz) { \
const char *szStart = ++sz; \ const char *szStart = ++sz; \
while ('\"' != *sz) \ while ('\"' != *sz && '\0' != *sz) \
++sz; \ ++sz; \
if ('\0' != *sz) { \
const char *szEnd = (sz++); \ const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \ out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \ ::memcpy(out.data, szStart, out.length); \
} \
} \
out.data[out.length] = '\0'; out.data[out.length] = '\0';
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// .MD5MESH parsing function // .MD5MESH parsing function

View File

@ -365,9 +365,7 @@ public:
static void ReportWarning (const char* warn, unsigned int line); static void ReportWarning (const char* warn, unsigned int line);
void ReportError (const char* error) { AI_WONT_RETURN void ReportError (const char* error) AI_WONT_RETURN_SUFFIX;
return ReportError(error, lineNumber);
}
void ReportWarning (const char* warn) { void ReportWarning (const char* warn) {
return ReportWarning(warn, lineNumber); return ReportWarning(warn, lineNumber);
@ -404,6 +402,9 @@ private:
unsigned int lineNumber; unsigned int lineNumber;
}; };
inline void MD5Parser::ReportError(const char* error) {
ReportError(error, lineNumber);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline bool MD5Parser::SkipLine(const char* in, const char** out) { inline bool MD5Parser::SkipLine(const char* in, const char** out) {
++lineNumber; ++lineNumber;

View File

@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() {
temp_bones_.resize(header_->numbones); temp_bones_.resize(header_->numbones);
// Create the main 'bones' node that will contain all MDL root bones.
aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES); aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
rootnode_children_.push_back(bones_node); rootnode_children_.push_back(bones_node);
bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; // Store roots bones IDs temporarily.
std::vector<int> roots;
// Create bone matrices in local space. // Create bone matrices in local space.
for (int i = 0; i < header_->numbones; ++i) { for (int i = 0; i < header_->numbones; ++i) {
aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]); aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]); aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
temp_bones_[i].absolute_transform = bone_node->mTransformation = temp_bones_[i].absolute_transform = bone_node->mTransformation =
@ -485,9 +487,11 @@ void HL1MDLLoader::read_bones() {
aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2])); aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
if (pbone[i].parent == -1) { if (pbone[i].parent == -1) {
bone_node->mParent = scene_->mRootNode; bone_node->mParent = bones_node;
roots.push_back(i); // This bone has no parent. Add it to the roots list.
} else { } else {
bone_node->mParent = bones_node->mChildren[pbone[i].parent]; bone_node->mParent = temp_bones_[pbone[i].parent].node;
temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
temp_bones_[i].absolute_transform = temp_bones_[i].absolute_transform =
temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
@ -496,6 +500,36 @@ void HL1MDLLoader::read_bones() {
temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform; temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
temp_bones_[i].offset_matrix.Inverse(); temp_bones_[i].offset_matrix.Inverse();
} }
// Allocate memory for each MDL root bone.
bones_node->mNumChildren = static_cast<unsigned int>(roots.size());
bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
// Build all bones children hierarchy starting from each MDL root bone.
for (size_t i = 0; i < roots.size(); ++i)
{
const TempBone &root_bone = temp_bones_[roots[i]];
bones_node->mChildren[i] = root_bone.node;
build_bone_children_hierarchy(root_bone);
}
}
void HL1MDLLoader::build_bone_children_hierarchy(const TempBone &bone)
{
if (bone.children.empty())
return;
aiNode* bone_node = bone.node;
bone_node->mNumChildren = static_cast<unsigned int>(bone.children.size());
bone_node->mChildren = new aiNode *[bone_node->mNumChildren];
// Build each child bone's hierarchy recursively.
for (size_t i = 0; i < bone.children.size(); ++i)
{
const TempBone &child_bone = temp_bones_[bone.children[i]];
bone_node->mChildren[i] = child_bone.node;
build_bone_children_hierarchy(child_bone);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -143,6 +143,14 @@ private:
*/ */
static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
/**
* \brief Build a bone's node children hierarchy.
*
* \param[in] bone The bone for which we must build all children hierarchy.
*/
struct TempBone;
void build_bone_children_hierarchy(const TempBone& bone);
/** Output scene to be filled */ /** Output scene to be filled */
aiScene *scene_; aiScene *scene_;
@ -198,11 +206,13 @@ private:
TempBone() : TempBone() :
node(nullptr), node(nullptr),
absolute_transform(), absolute_transform(),
offset_matrix() {} offset_matrix(),
children() {}
aiNode *node; aiNode *node;
aiMatrix4x4 absolute_transform; aiMatrix4x4 absolute_transform;
aiMatrix4x4 offset_matrix; aiMatrix4x4 offset_matrix;
std::vector<int> children; // Bone children
}; };
std::vector<TempBone> temp_bones_; std::vector<TempBone> temp_bones_;

View File

@ -271,10 +271,16 @@ void MDLImporter::InternReadFile(const std::string &pFile,
} }
} }
// ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range
bool MDLImporter::IsPosValid(const void *szPos) const {
return szPos && (const unsigned char *)szPos <= this->mBuffer + this->iFileSize && szPos >= this->mBuffer;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range // Check whether we're still inside the valid file range
void MDLImporter::SizeCheck(const void *szPos) { void MDLImporter::SizeCheck(const void *szPos) {
if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize) { if (!IsPosValid(szPos)) {
throw DeadlyImportError("Invalid MDL file. The file is too small " throw DeadlyImportError("Invalid MDL file. The file is too small "
"or contains invalid data."); "or contains invalid data.");
} }
@ -284,7 +290,7 @@ void MDLImporter::SizeCheck(const void *szPos) {
// Just for debugging purposes // Just for debugging purposes
void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) { void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
ai_assert(nullptr != szFile); ai_assert(nullptr != szFile);
if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) { if (!IsPosValid(szPos)) {
// remove a directory if there is one // remove a directory if there is one
const char *szFilePtr = ::strrchr(szFile, '\\'); const char *szFilePtr = ::strrchr(szFile, '\\');
if (!szFilePtr) { if (!szFilePtr) {
@ -975,7 +981,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones)
} }
// store the name of the bone // store the name of the bone
pcOutBone->mName.length = (size_t)iMaxLen; pcOutBone->mName.length = static_cast<ai_uint32>(iMaxLen);
::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length); ::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length);
pcOutBone->mName.data[pcOutBone->mName.length] = '\0'; pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
} }

View File

@ -139,7 +139,7 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Import a CS:S/HL2 MDL file (not fully implemented) /** Import a CS:S/HL2 MDL file (not fully implemented)
*/ */
void InternReadFile_HL2( ); AI_WONT_RETURN void InternReadFile_HL2( ) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Check whether a given position is inside the valid range /** Check whether a given position is inside the valid range
@ -150,6 +150,7 @@ protected:
*/ */
void SizeCheck(const void* szPos); void SizeCheck(const void* szPos);
void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
bool IsPosValid(const void* szPos) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Validate the header data structure of a game studio MDL7 file /** Validate the header data structure of a game studio MDL7 file

View File

@ -481,6 +481,8 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
pcNew->achFormatHint[2] = 's'; pcNew->achFormatHint[2] = 's';
pcNew->achFormatHint[3] = '\0'; pcNew->achFormatHint[3] = '\0';
SizeCheck(szCurrent + pcNew->mWidth);
pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth]; pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
memcpy(pcNew->pcData, szCurrent, pcNew->mWidth); memcpy(pcNew->pcData, szCurrent, pcNew->mWidth);
szCurrent += iWidth; szCurrent += iWidth;
@ -493,12 +495,12 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
aiString szFile; aiString szFile;
const size_t iLen = strlen((const char *)szCurrent); const size_t iLen = strlen((const char *)szCurrent);
size_t iLen2 = iLen + 1; size_t iLen2 = iLen > (MAXLEN - 1) ? (MAXLEN - 1) : iLen;
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
memcpy(szFile.data, (const char *)szCurrent, iLen2); memcpy(szFile.data, (const char *)szCurrent, iLen2);
szFile.data[iLen2] = '\0';
szFile.length = static_cast<ai_uint32>(iLen2); szFile.length = static_cast<ai_uint32>(iLen2);
szCurrent += iLen2; szCurrent += iLen2 + 1;
// place this as diffuse texture // place this as diffuse texture
pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0)); pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
@ -703,7 +705,14 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7(
tex.pcData = bad_texel; tex.pcData = bad_texel;
tex.mHeight = iHeight; tex.mHeight = iHeight;
tex.mWidth = iWidth; tex.mWidth = iWidth;
try {
ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex); ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
} catch (...) {
// FIX: Important, otherwise the destructor will crash
tex.pcData = nullptr;
throw;
}
// FIX: Important, otherwise the destructor will crash // FIX: Important, otherwise the destructor will crash
tex.pcData = nullptr; tex.pcData = nullptr;

View File

@ -269,7 +269,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
dynamic_cast<pmx::PmxVertexSkinningSDEF *>(v->skinning.get()); dynamic_cast<pmx::PmxVertexSkinningSDEF *>(v->skinning.get());
switch (v->skinning_type) { switch (v->skinning_type) {
case pmx::PmxVertexSkinningType::BDEF1: case pmx::PmxVertexSkinningType::BDEF1:
bone_vertex_map[vsBDEF1_ptr->bone_index].emplace_back(index, 1.0); bone_vertex_map[vsBDEF1_ptr->bone_index].emplace_back(index, static_cast<ai_real>(1));
break; break;
case pmx::PmxVertexSkinningType::BDEF2: case pmx::PmxVertexSkinningType::BDEF2:
bone_vertex_map[vsBDEF2_ptr->bone_index1].emplace_back(index, vsBDEF2_ptr->bone_weight); bone_vertex_map[vsBDEF2_ptr->bone_index1].emplace_back(index, vsBDEF2_ptr->bone_weight);

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <assimp/types.h>
#include "MMDCpp14.h" #include "MMDCpp14.h"
namespace pmx namespace pmx
@ -730,7 +731,7 @@ namespace pmx
std::unique_ptr<PmxAncherRigidBody []> anchers; std::unique_ptr<PmxAncherRigidBody []> anchers;
int pin_vertex_count; int pin_vertex_count;
std::unique_ptr<int []> pin_vertices; std::unique_ptr<int []> pin_vertices;
void Read(std::istream *stream, PmxSetting *setting); AI_WONT_RETURN void Read(std::istream *stream, PmxSetting *setting) AI_WONT_RETURN_SUFFIX;
}; };
class PmxModel class PmxModel

View File

@ -486,7 +486,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) { for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++j) {
aiFace& f = m->mFaces[j]; aiFace& f = m->mFaces[j];
if (g.triangles[j]>triangles.size()) { if (g.triangles[j] >= triangles.size()) {
throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed"); throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
} }
@ -494,7 +494,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
f.mIndices = new unsigned int[f.mNumIndices=3]; f.mIndices = new unsigned int[f.mNumIndices=3];
for (unsigned int k = 0; k < 3; ++k,++n) { for (unsigned int k = 0; k < 3; ++k,++n) {
if (t.indices[k]>vertices.size()) { if (t.indices[k] >= vertices.size()) {
throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed"); throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
} }

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/StreamReader.h> #include <assimp/StreamReader.h>
#include <map> #include <map>
#include <limits>
using namespace Assimp; using namespace Assimp;
@ -160,6 +161,9 @@ void NDOImporter::InternReadFile( const std::string& pFile,
temp = file_format >= 12 ? reader.GetU4() : reader.GetU2(); temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
head = (const char*)reader.GetPtr(); head = (const char*)reader.GetPtr();
if (std::numeric_limits<unsigned int>::max() - 76 < temp) {
throw DeadlyImportError("Invalid name length");
}
reader.IncPtr(temp + 76); /* skip unknown stuff */ reader.IncPtr(temp + 76); /* skip unknown stuff */
obj.name = std::string(head, temp); obj.name = std::string(head, temp);

View File

@ -284,7 +284,7 @@ void OFFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
for (unsigned int i = 0; i < numFaces; ) { for (unsigned int i = 0; i < numFaces; ) {
if(!GetNextLine(buffer,line)) { if(!GetNextLine(buffer,line)) {
ASSIMP_LOG_ERROR("OFF: The number of faces in the header is incorrect"); ASSIMP_LOG_ERROR("OFF: The number of faces in the header is incorrect");
break; throw DeadlyImportError("OFF: The number of faces in the header is incorrect");
} }
unsigned int idx; unsigned int idx;
sz = line; SkipSpaces(&sz); sz = line; SkipSpaces(&sz);

View File

@ -239,8 +239,6 @@ struct Mesh {
unsigned int m_uiMaterialIndex; unsigned int m_uiMaterialIndex;
/// True, if normals are stored. /// True, if normals are stored.
bool m_hasNormals; bool m_hasNormals;
/// True, if vertex colors are stored.
bool m_hasVertexColors;
/// Constructor /// Constructor
explicit Mesh(const std::string &name) : explicit Mesh(const std::string &name) :

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2023, assimp team
All rights reserved. All rights reserved.
@ -84,7 +84,6 @@ ObjFileImporter::ObjFileImporter() :
// Destructor. // Destructor.
ObjFileImporter::~ObjFileImporter() { ObjFileImporter::~ObjFileImporter() {
delete m_pRootObject; delete m_pRootObject;
m_pRootObject = nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -270,7 +269,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) { for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
unsigned int meshId = pObject->m_Meshes[i]; unsigned int meshId = pObject->m_Meshes[i];
aiMesh *pMesh = createTopology(pModel, pObject, meshId); aiMesh *pMesh = createTopology(pModel, pObject, meshId);
if (pMesh) { if (pMesh != nullptr) {
if (pMesh->mNumFaces > 0) { if (pMesh->mNumFaces > 0) {
MeshArray.push_back(pMesh); MeshArray.push_back(pMesh);
} else { } else {
@ -331,7 +330,6 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) { for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
const ObjFile::Face *inp = pObjMesh->m_Faces[index]; const ObjFile::Face *inp = pObjMesh->m_Faces[index];
//ai_assert(nullptr != inp);
if (inp->mPrimitiveType == aiPrimitiveType_LINE) { if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1); pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
@ -500,6 +498,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
if (vertexIndex) { if (vertexIndex) {
if (!last) { if (!last) {
if (pMesh->mNumVertices <= newIndex + 1) {
throw DeadlyImportError("OBJ: bad vertex index");
}
pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex]; pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) { if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex]; pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];

View File

@ -252,8 +252,8 @@ void ObjFileMtlImporter::load() {
case 'a': // Anisotropy case 'a': // Anisotropy
{ {
++m_DataIt; ++m_DataIt;
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
if (m_pModel->mCurrentMaterial != nullptr) if (m_pModel->mCurrentMaterial != nullptr)
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine); m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break; } break;
@ -371,6 +371,7 @@ void ObjFileMtlImporter::getTexture() {
if (m_pModel->mCurrentMaterial == nullptr) { if (m_pModel->mCurrentMaterial == nullptr) {
m_pModel->mCurrentMaterial = new ObjFile::Material(); m_pModel->mCurrentMaterial = new ObjFile::Material();
m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material"); m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material");
m_pModel->mMaterialMap["Empty_Material"] = m_pModel->mCurrentMaterial;
} }
const char *pPtr(&(*m_DataIt)); const char *pPtr(&(*m_DataIt));

View File

@ -156,9 +156,17 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
// read in vertex definition (homogeneous coords) // read in vertex definition (homogeneous coords)
getHomogeneousVector3(m_pModel->mVertices); getHomogeneousVector3(m_pModel->mVertices);
} else if (numComponents == 6) { } else if (numComponents == 6) {
// fill previous omitted vertex-colors by default
if (m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
}
// read vertex and vertex-color // read vertex and vertex-color
getTwoVectors3(m_pModel->mVertices, m_pModel->mVertexColors); getTwoVectors3(m_pModel->mVertices, m_pModel->mVertexColors);
} }
// append omitted vertex-colors as default for the end if any vertex-color exists
if (!m_pModel->mVertexColors.empty() && m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
}
} else if (*m_DataIt == 't') { } else if (*m_DataIt == 't') {
// read in texture coordinate ( 2D or 3D ) // read in texture coordinate ( 2D or 3D )
++m_DataIt; ++m_DataIt;
@ -236,7 +244,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
getNameNoSpace(m_DataIt, m_DataItEnd, name); getNameNoSpace(m_DataIt, m_DataItEnd, name);
insideCstype = name == "cstype"; insideCstype = name == "cstype";
goto pf_skip_line; goto pf_skip_line;
} break; }
default: { default: {
pf_skip_line: pf_skip_line:
@ -456,8 +464,19 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
iPos = 0; iPos = 0;
} else { } else {
//OBJ USES 1 Base ARRAYS!!!! //OBJ USES 1 Base ARRAYS!!!!
const char *token = &(*m_DataIt); int iVal;
const int iVal = ::atoi(token); auto end = m_DataIt;
// find either the buffer end or the '\0'
while (end < m_DataItEnd && *end != '\0')
++end;
// avoid temporary string allocation if there is a zero
if (end != m_DataItEnd) {
iVal = ::atoi(&(*m_DataIt));
} else {
// otherwise make a zero terminated copy, which is safe to pass to atoi
std::string number(&(*m_DataIt), m_DataItEnd - m_DataIt);
iVal = ::atoi(number.c_str());
}
// increment iStep position based off of the sign and # of digits // increment iStep position based off of the sign and # of digits
int tmp = iVal; int tmp = iVal;

View File

@ -60,17 +60,17 @@ namespace Ogre {
class OgreImporter : public BaseImporter { class OgreImporter : public BaseImporter {
public: public:
/// BaseImporter override. /// BaseImporter override.
virtual bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override; bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected: protected:
/// BaseImporter override. /// BaseImporter override.
virtual void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override; void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
/// BaseImporter override. /// BaseImporter override.
virtual const aiImporterDesc *GetInfo() const override; const aiImporterDesc *GetInfo() const override;
/// BaseImporter override. /// BaseImporter override.
virtual void SetupProperties(const Importer *pImp) override; void SetupProperties(const Importer *pImp) override;
private: private:
/// Read materials referenced by the @c mesh to @c pScene. /// Read materials referenced by the @c mesh to @c pScene.

View File

@ -57,7 +57,7 @@ namespace Assimp {
namespace Ogre { namespace Ogre {
//AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; //AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) { AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
if (!error.empty()) { if (!error.empty()) {
throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'"); throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'");
@ -128,7 +128,6 @@ bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name)
} }
ThrowAttibuteError(xmlNode.name(), name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'"); ThrowAttibuteError(xmlNode.name(), name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
return false;
} }
// Mesh XML constants // Mesh XML constants
@ -490,7 +489,7 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
OgreXmlSerializer serializer(xmlParser.get()); OgreXmlSerializer serializer(xmlParser.get());
XmlNode root = xmlParser->getRootNode(); XmlNode root = xmlParser->getRootNode();
if (std::string(root.name()) != nnSkeleton) { if (std::string(root.name()) != nnSkeleton) {
printf("\nSkeleton is not a valid root: %s\n", root.name()); ASSIMP_LOG_VERBOSE_DEBUG("nSkeleton is not a valid root: ", root.name(), ".");
for (auto &a : root.children()) { for (auto &a : root.children()) {
if (std::string(a.name()) == nnSkeleton) { if (std::string(a.name()) == nnSkeleton) {
root = a; root = a;

View File

@ -261,7 +261,6 @@ OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::stri
OpenGEXImporter::OpenGEXImporter() : OpenGEXImporter::OpenGEXImporter() :
m_root(nullptr), m_root(nullptr),
m_nodeChildMap(), m_nodeChildMap(),
m_meshCache(),
m_mesh2refMap(), m_mesh2refMap(),
m_material2refMap(), m_material2refMap(),
m_ctx(nullptr), m_ctx(nullptr),
@ -461,14 +460,12 @@ void OpenGEXImporter::handleMetricNode(DDLNode *node, aiScene * /*pScene*/) {
void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleNameNode(DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == m_currentNode) { if (nullptr == m_currentNode) {
throw DeadlyImportError("No current node for name."); throw DeadlyImportError("No current node for name.");
return;
} }
Value *val(node->getValue()); Value *val(node->getValue());
if (nullptr != val) { if (nullptr != val) {
if (Value::ValueType::ddl_string != val->m_type) { if (Value::ValueType::ddl_string != val->m_type) {
throw DeadlyImportError("OpenGEX: invalid data type for value in node name."); throw DeadlyImportError("OpenGEX: invalid data type for value in node name.");
return;
} }
const std::string name(val->getString()); const std::string name(val->getString());
@ -509,7 +506,6 @@ static void getRefNames(DDLNode *node, std::vector<std::string> &names) {
void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == m_currentNode) { if (nullptr == m_currentNode) {
throw DeadlyImportError("No parent node for name."); throw DeadlyImportError("No parent node for name.");
return;
} }
std::vector<std::string> objRefNames; std::vector<std::string> objRefNames;
@ -533,7 +529,6 @@ void OpenGEXImporter::handleObjectRefNode(DDLNode *node, aiScene * /*pScene*/) {
void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleMaterialRefNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == m_currentNode) { if (nullptr == m_currentNode) {
throw DeadlyImportError("No parent node for name."); throw DeadlyImportError("No parent node for name.");
return;
} }
std::vector<std::string> matRefNames; std::vector<std::string> matRefNames;
@ -673,14 +668,12 @@ static void setMatrix(aiNode *node, DataArrayList *transformData) {
void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleTransformNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == m_currentNode) { if (nullptr == m_currentNode) {
throw DeadlyImportError("No parent node for name."); throw DeadlyImportError("No parent node for name.");
return;
} }
DataArrayList *transformData(node->getDataArrayList()); DataArrayList *transformData(node->getDataArrayList());
if (nullptr != transformData) { if (nullptr != transformData) {
if (transformData->m_numItems != 16) { if (transformData->m_numItems != 16) {
throw DeadlyImportError("Invalid number of data for transform matrix."); throw DeadlyImportError("Invalid number of data for transform matrix.");
return;
} }
setMatrix(m_currentNode, transformData); setMatrix(m_currentNode, transformData);
} }
@ -836,7 +829,6 @@ static void copyColor4DArray(size_t numItems, DataArrayList *vaList, aiColor4D *
void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == node) { if (nullptr == node) {
throw DeadlyImportError("No parent node for name."); throw DeadlyImportError("No parent node for name.");
return;
} }
Property *prop = node->getProperties(); Property *prop = node->getProperties();
@ -877,12 +869,10 @@ void OpenGEXImporter::handleVertexArrayNode(ODDLParser::DDLNode *node, aiScene *
void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) { void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene * /*pScene*/) {
if (nullptr == node) { if (nullptr == node) {
throw DeadlyImportError("No parent node for name."); throw DeadlyImportError("No parent node for name.");
return;
} }
if (nullptr == m_currentMesh) { if (nullptr == m_currentMesh) {
throw DeadlyImportError("No current mesh for index data found."); throw DeadlyImportError("No current mesh for index data found.");
return;
} }
DataArrayList *vaList = node->getDataArrayList(); DataArrayList *vaList = node->getDataArrayList();

View File

@ -308,8 +308,8 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
streamBuffer.getNextLine(buffer); streamBuffer.getNextLine(buffer);
pCur = (char *)&buffer[0]; pCur = (char *)&buffer[0];
// skip all comments // skip all comments and go to next line
PLY::DOM::SkipComments(buffer); if (PLY::DOM::SkipComments(buffer)) continue;
PLY::Property prop; PLY::Property prop;
if (!PLY::Property::ParseProperty(buffer, &prop)) if (!PLY::Property::ParseProperty(buffer, &prop))
@ -420,7 +420,7 @@ bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char>
if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) { if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) {
// add the element to the list of elements // add the element to the list of elements
alElements.push_back(out); alElements.push_back(out);
} else if (TokenMatch(buffer, "end_header", 10)) { //checks for /n ending, if it doesn't end with /r/n } else if (TokenMatch(buffer, "end_header", 10)) {
// we have reached the end of the header // we have reached the end of the header
break; break;
} else { } else {

View File

@ -296,9 +296,7 @@ class PropertyInstance
public: public:
//! Default constructor //! Default constructor
PropertyInstance() AI_NO_EXCEPT { PropertyInstance() AI_NO_EXCEPT = default;
// empty
}
union ValueUnion union ValueUnion
{ {
@ -359,10 +357,7 @@ public:
class ElementInstance { class ElementInstance {
public: public:
//! Default constructor //! Default constructor
ElementInstance() AI_NO_EXCEPT ElementInstance() AI_NO_EXCEPT = default;
: alProperties() {
// empty
}
//! List of all parsed properties //! List of all parsed properties
std::vector< PropertyInstance > alProperties; std::vector< PropertyInstance > alProperties;
@ -386,10 +381,7 @@ class ElementInstanceList
public: public:
//! Default constructor //! Default constructor
ElementInstanceList() AI_NO_EXCEPT ElementInstanceList() AI_NO_EXCEPT = default;
: alInstances() {
// empty
}
//! List of all element instances //! List of all element instances
std::vector< ElementInstance > alInstances; std::vector< ElementInstance > alInstances;
@ -413,11 +405,7 @@ class DOM
public: public:
//! Default constructor //! Default constructor
DOM() AI_NO_EXCEPT DOM() AI_NO_EXCEPT = default;
: alElements()
, alElementData() {
}
//! Contains all elements of the file format //! Contains all elements of the file format

View File

@ -169,19 +169,7 @@ struct Q3BSPModel {
std::vector<char> m_EntityData; std::vector<char> m_EntityData;
std::string m_ModelName; std::string m_ModelName;
Q3BSPModel() : Q3BSPModel() = default;
m_Data(),
m_Lumps(),
m_Vertices(),
m_Faces(),
m_Indices(),
m_Textures(),
m_Lightmaps(),
m_EntityData(),
m_ModelName()
{
// empty
}
~Q3BSPModel() { ~Q3BSPModel() {
for ( unsigned int i=0; i<m_Lumps.size(); i++ ) { for ( unsigned int i=0; i<m_Lumps.size(); i++ ) {

View File

@ -139,7 +139,7 @@ static void normalizePathName(const std::string &rPath, std::string &normalizedP
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. // Constructor.
Q3BSPFileImporter::Q3BSPFileImporter() : Q3BSPFileImporter::Q3BSPFileImporter() :
m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr), m_MaterialLookupMap(), mTextures() { m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr) {
// empty // empty
} }

View File

@ -382,11 +382,10 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
// TODO // TODO
goto outer; goto outer;
} break; }
default: default:
throw DeadlyImportError("Quick3D: Unknown chunk"); throw DeadlyImportError("Quick3D: Unknown chunk");
break;
}; };
} }
outer: outer:

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