Merge branch 'master' into dependabot/github_actions/lukka/run-cmake-10
commit
87ddb3c69f
|
@ -1,2 +0,0 @@
|
|||
service_name: travis-pro
|
||||
repo_token: GZXuNlublKFy7HAewHAZLk5ZwgipTFAOA
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
- name: Set Windows specific CMake arguments
|
||||
if: contains(matrix.name, 'windows')
|
||||
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
|
||||
if: contains(matrix.name, 'hunter')
|
||||
|
|
|
@ -57,3 +57,13 @@ jobs:
|
|||
- name: test
|
||||
run: cd build/bin && ./unit
|
||||
shell: bash
|
||||
|
||||
job3:
|
||||
name: printf-sanitizer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: run scan_printf script
|
||||
run: ./scripts/scan_printf.sh
|
||||
shell: bash
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Open Asset Import Library (assimp)
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2006-2022, assimp team
|
||||
# Copyright (c) 2006-2023, assimp team
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
|
@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
|||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
include("cmake-modules/HunterGate.cmake")
|
||||
HunterGate(
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
|
||||
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz"
|
||||
SHA1 "e6396699e414120e32557fe92db097b7655b760b"
|
||||
)
|
||||
|
||||
add_definitions(-DASSIMP_USE_HUNTER)
|
||||
|
@ -84,10 +84,6 @@ OPTION( ASSIMP_NO_EXPORT
|
|||
"Disable Assimp's export functionality."
|
||||
OFF
|
||||
)
|
||||
OPTION( ASSIMP_BUILD_ZLIB
|
||||
"Build your own zlib"
|
||||
OFF
|
||||
)
|
||||
OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
|
||||
"If the supplementary tools for Assimp are built in addition to the library."
|
||||
OFF
|
||||
|
@ -134,6 +130,18 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
|
|||
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)
|
||||
# Use subset of Windows.h
|
||||
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
|
||||
|
@ -260,30 +268,37 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
|
|||
SET(CMAKE_CXX_STANDARD 17)
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
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
|
||||
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
|
||||
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||
ELSE()
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
SET(LIBSTDC++_LIBRARIES -lstdc++)
|
||||
ENDIF()
|
||||
ELSEIF(MSVC)
|
||||
# enable multi-core compilation with MSVC
|
||||
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
|
||||
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
|
||||
ADD_COMPILE_OPTIONS(/bigobj)
|
||||
ELSE() # msvc
|
||||
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
|
||||
ADD_COMPILE_OPTIONS(/MP /bigobj)
|
||||
ENDIF()
|
||||
|
||||
# disable "elements of array '' will be default initialized" warning on MSVC2013
|
||||
IF(MSVC12)
|
||||
ADD_COMPILE_OPTIONS(/wd4351)
|
||||
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_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")
|
||||
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
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")
|
||||
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 )
|
||||
# Use GNUInstallDirs for Unix predefined directories
|
||||
INCLUDE(GNUInstallDirs)
|
||||
|
@ -488,7 +495,11 @@ ELSE()
|
|||
FIND_PACKAGE(ZLIB)
|
||||
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")
|
||||
INCLUDE(CheckIncludeFile)
|
||||
INCLUDE(CheckTypeSize)
|
||||
|
|
|
@ -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.
|
16
Dockerfile
16
Dockerfile
|
@ -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
|
||||
|
||||
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update && apt-get install -y gcc-4.9 g++-4.9 && \
|
||||
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
|
||||
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
|
@ -19,7 +14,8 @@ WORKDIR /opt/assimp
|
|||
|
||||
RUN git checkout master \
|
||||
&& mkdir build && cd build && \
|
||||
cmake \
|
||||
cmake -G 'Ninja' \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DASSIMP_BUILD_ASSIMP_TOOLS=ON \
|
||||
.. && \
|
||||
make && make install
|
||||
ninja -j4 && ninja install
|
||||
|
|
38
Readme.md
38
Readme.md
|
@ -1,6 +1,8 @@
|
|||
Open Asset Import Library (assimp)
|
||||
==================================
|
||||
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
||||
|
||||
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
|
||||
|
||||
### Current project status ###
|
||||
[](https://opencollective.com/assimp)
|
||||

|
||||
|
@ -14,7 +16,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
|
|||
[](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
|
||||
[](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
|
||||
[](https://lgtm.com/projects/g/assimp/assimp/alerts/)
|
||||
<br>
|
||||
|
||||
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
|
||||
|
@ -23,15 +24,19 @@ Additionally, assimp features various __mesh post processing tools__: normals an
|
|||
### Latest Doc's ###
|
||||
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
|
||||
|
||||
### Get involved ###
|
||||
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
|
||||
<br>
|
||||
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
|
||||
<br>
|
||||
Please check our Wiki as well: https://github.com/assimp/assimp/wiki
|
||||
### Prebuild binaries ###
|
||||
Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib)
|
||||
|
||||
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
|
||||
|
||||
### Communities ###
|
||||
- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions)
|
||||
- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/)
|
||||
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
|
||||
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
|
||||
|
||||
And we also have a Gitter-channel:Gitter [](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
|
||||
|
||||
#### Supported file formats ####
|
||||
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md)
|
||||
|
||||
|
@ -66,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.
|
||||
/test Unit- and regression tests, test suite of models
|
||||
/tools Tools (old assimp viewer, command line `assimp`)
|
||||
/samples A small number of samples to illustrate possible
|
||||
use cases for Assimp
|
||||
/samples A small number of samples to illustrate possible use-cases for Assimp
|
||||
|
||||
The source code is organized in the following way:
|
||||
|
||||
code/Common The base implementation for importers and the infrastructure
|
||||
code/CApi Special implementations which are only used for the C-API
|
||||
code/Geometry A collection of geometry tools
|
||||
code/Material The material system
|
||||
code/PBR An exporter for physical based models
|
||||
code/PostProcessing The post-processing steps
|
||||
code/AssetLib/<FormatName> Implementation for import and export for the format
|
||||
|
||||
### Where to get help ###
|
||||
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 [](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
|
||||
|
||||
### Contributing ###
|
||||
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
||||
a pull request with your changes against the main repository's `master` branch.
|
||||
|
|
|
@ -322,7 +322,6 @@ struct Texture {
|
|||
//! Default constructor
|
||||
Texture() AI_NO_EXCEPT
|
||||
: mTextureBlend(0.0f),
|
||||
mMapName(),
|
||||
mOffsetU(0.0),
|
||||
mOffsetV(0.0),
|
||||
mScaleU(1.0),
|
||||
|
@ -334,51 +333,11 @@ struct Texture {
|
|||
mTextureBlend = get_qnan();
|
||||
}
|
||||
|
||||
Texture(const Texture &other) :
|
||||
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(const Texture &other) = default;
|
||||
|
||||
Texture(Texture &&other) AI_NO_EXCEPT : 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) {
|
||||
// empty
|
||||
}
|
||||
Texture(Texture &&other) AI_NO_EXCEPT = default;
|
||||
|
||||
Texture &operator=(Texture &&other) AI_NO_EXCEPT {
|
||||
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;
|
||||
}
|
||||
Texture &operator=(Texture &&other) AI_NO_EXCEPT = default;
|
||||
|
||||
//! Specifies the blend factor for the texture
|
||||
ai_real mTextureBlend;
|
||||
|
@ -436,83 +395,9 @@ struct Material {
|
|||
// empty
|
||||
}
|
||||
|
||||
Material(const Material &other) :
|
||||
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
|
||||
}
|
||||
Material(const Material &other) = default;
|
||||
|
||||
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
|
||||
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
|
||||
}
|
||||
virtual ~Material() = default;
|
||||
|
||||
//! Name of the material
|
||||
std::string mName;
|
||||
|
|
|
@ -266,8 +266,15 @@ void Discreet3DSImporter::ParseMainChunk() {
|
|||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code-return"
|
||||
#endif
|
||||
// recursively continue processing this hierarchy level
|
||||
return ParseMainChunk();
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -68,7 +68,7 @@ using namespace D3DS;
|
|||
class Discreet3DSImporter : public BaseImporter {
|
||||
public:
|
||||
Discreet3DSImporter();
|
||||
~Discreet3DSImporter();
|
||||
~Discreet3DSImporter() override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
|
|
|
@ -69,9 +69,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
virtual ~Resource() {
|
||||
// empty
|
||||
}
|
||||
virtual ~Resource() = default;
|
||||
|
||||
virtual ResourceType getType() const {
|
||||
return ResourceType::RT_Unknown;
|
||||
|
@ -95,7 +93,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~EmbeddedTexture() = default;
|
||||
~EmbeddedTexture() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_EmbeddedTexture2D;
|
||||
|
@ -112,7 +110,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~Texture2DGroup() = default;
|
||||
~Texture2DGroup() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_Texture2DGroup;
|
||||
|
@ -129,7 +127,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~BaseMaterials() = default;
|
||||
~BaseMaterials() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_BaseMaterials;
|
||||
|
@ -154,7 +152,7 @@ public:
|
|||
// empty
|
||||
}
|
||||
|
||||
~Object() = default;
|
||||
~Object() override = default;
|
||||
|
||||
ResourceType getType() const override {
|
||||
return ResourceType::RT_Object;
|
||||
|
|
|
@ -83,7 +83,7 @@ void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScen
|
|||
namespace D3MF {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
|
|||
// deal with zip-bug
|
||||
rootFile = rootFile.substr(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ void XmlSerializer::ImportXml(aiScene *scene) {
|
|||
if (nullptr == scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
scene->mRootNode = new aiNode(XmlTag::RootTag);
|
||||
XmlNode node = mXmlParser->getRootNode().child(XmlTag::model);
|
||||
if (node.empty()) {
|
||||
|
@ -444,7 +444,7 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
|
|||
}
|
||||
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -227,7 +227,9 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
|||
}
|
||||
} else if (TokenMatch(buffer, "texture", 7)) {
|
||||
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)) {
|
||||
SkipSpaces(&buffer);
|
||||
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
|
||||
|
@ -351,8 +353,8 @@ void AC3DImporter::ConvertMaterial(const Object &object,
|
|||
s.Set(matSrc.name);
|
||||
matDest.AddProperty(&s, AI_MATKEY_NAME);
|
||||
}
|
||||
if (object.texture.length()) {
|
||||
s.Set(object.texture);
|
||||
if (!object.textures.empty()) {
|
||||
s.Set(object.textures[0]);
|
||||
matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
||||
// UV transformation
|
||||
|
@ -532,7 +534,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
|||
// allocate UV coordinates, but only if the texture name for the
|
||||
// surface is not empty
|
||||
aiVector3D *uv = nullptr;
|
||||
if (object.texture.length()) {
|
||||
if (!object.textures.empty()) {
|
||||
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mNumUVComponents[0] = 2;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,6 @@ public:
|
|||
type(World),
|
||||
name(),
|
||||
children(),
|
||||
texture(),
|
||||
texRepeat(1.f, 1.f),
|
||||
texOffset(0.0f, 0.0f),
|
||||
rotation(),
|
||||
|
@ -151,7 +150,8 @@ public:
|
|||
std::vector<Object> children;
|
||||
|
||||
// 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)
|
||||
aiVector2D texRepeat, texOffset;
|
||||
|
|
|
@ -83,11 +83,7 @@ void AMFImporter::Clear() {
|
|||
|
||||
AMFImporter::AMFImporter() AI_NO_EXCEPT :
|
||||
mNodeElement_Cur(nullptr),
|
||||
mXmlParser(nullptr),
|
||||
mUnit(),
|
||||
mVersion(),
|
||||
mMaterial_Converted(),
|
||||
mTexture_Converted() {
|
||||
mXmlParser(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
|
@ -282,11 +282,11 @@ public:
|
|||
bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
|
||||
bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
|
||||
bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
|
||||
void Throw_CloseNotFound(const std::string &nodeName);
|
||||
void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName);
|
||||
void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName);
|
||||
void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription);
|
||||
void Throw_ID_NotFound(const std::string &pID) const;
|
||||
AI_WONT_RETURN void Throw_CloseNotFound(const std::string &nodeName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Throw_ID_NotFound(const std::string &pID) const AI_WONT_RETURN_SUFFIX;
|
||||
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
|
||||
bool XML_SearchNode(const std::string &nodeName);
|
||||
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
|
||||
|
|
|
@ -88,9 +88,7 @@ public:
|
|||
std::list<AMFNodeElementBase *> Child; ///< Child elements.
|
||||
|
||||
public: /// Destructor, virtual..
|
||||
virtual ~AMFNodeElementBase() {
|
||||
// empty
|
||||
}
|
||||
virtual ~AMFNodeElementBase() = default;
|
||||
|
||||
/// Disabled copy constructor and co.
|
||||
AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete;
|
||||
|
@ -103,7 +101,7 @@ protected:
|
|||
/// \param [in] pType - element type.
|
||||
/// \param [in] pParent - parent element.
|
||||
AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
|
||||
Type(pType), ID(), Parent(pParent), Child() {
|
||||
Type(pType), Parent(pParent) {
|
||||
// empty
|
||||
}
|
||||
}; // class IAMFImporter_NodeElement
|
||||
|
@ -174,7 +172,7 @@ struct AMFColor : public AMFNodeElementBase {
|
|||
/// @brief Constructor.
|
||||
/// @param [in] pParent - pointer to parent node.
|
||||
AMFColor(AMFNodeElementBase *pParent) :
|
||||
AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() {
|
||||
AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -270,7 +268,7 @@ struct AMFTexMap : public AMFNodeElementBase {
|
|||
/// Constructor.
|
||||
/// \param [in] pParent - pointer to parent node.
|
||||
AMFTexMap(AMFNodeElementBase *pParent) :
|
||||
AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() {
|
||||
AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{} {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
|
|
@ -815,6 +815,7 @@ nl_clean_loop:
|
|||
for (; next_it != nodeArray.end(); ++next_it) {
|
||||
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
|
||||
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
|
||||
// FIXME: this leaks memory on test models test8.amf and test9.amf
|
||||
nodeArray.erase(nl_it);
|
||||
|
||||
goto nl_clean_loop;
|
||||
|
|
|
@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
// internal headers
|
||||
|
@ -322,21 +321,6 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
|
|||
aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
|
||||
nd->mNodeName.Set(me->mName + ".Target");
|
||||
|
||||
// If there is no input position channel we will need
|
||||
// to supply the default position from the node's
|
||||
// local transformation matrix.
|
||||
/*TargetAnimationHelper helper;
|
||||
if (me->mAnim.akeyPositions.empty())
|
||||
{
|
||||
aiMatrix4x4& mat = (*i)->mTransform;
|
||||
helper.SetFixedMainAnimationChannel(aiVector3D(
|
||||
mat.a4, mat.b4, mat.c4));
|
||||
}
|
||||
else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
|
||||
helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
|
||||
|
||||
helper.Process(&me->mTargetAnim.akeyPositions);*/
|
||||
|
||||
// Allocate the key array and fill it
|
||||
nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
|
||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||
|
|
|
@ -304,7 +304,6 @@ void Parser::Parse() {
|
|||
}
|
||||
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -480,6 +479,11 @@ void Parser::ParseLV1MaterialListBlock() {
|
|||
if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) {
|
||||
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
|
||||
m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
|
||||
continue;
|
||||
|
@ -734,7 +738,6 @@ void Parser::ParseLV3MapBlock(Texture &map) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -859,7 +862,6 @@ void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) {
|
|||
}
|
||||
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -883,7 +885,6 @@ void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) {
|
|||
}
|
||||
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");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
|
||||
|
@ -1310,7 +1310,6 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("2", "*MESH");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
|
||||
|
@ -1344,7 +1343,6 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
|
||||
|
@ -1414,7 +1412,6 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshVertexListBlock(
|
||||
|
@ -1443,7 +1440,6 @@ void Parser::ParseLV3MeshVertexListBlock(
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
|
||||
|
@ -1503,7 +1498,6 @@ void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
|
||||
|
@ -1532,7 +1526,6 @@ void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
|
||||
|
@ -1567,7 +1560,6 @@ void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) {
|
||||
|
@ -1595,7 +1587,6 @@ void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh)
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
|
||||
|
@ -1623,7 +1614,6 @@ void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh)
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
|
||||
|
@ -1681,7 +1671,6 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
|
|||
}
|
||||
AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshFace(ASE::Face &out) {
|
||||
|
|
|
@ -56,5 +56,5 @@ namespace Assimp {
|
|||
void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/);
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // AI_ASSBINEXPORTER_H_INC
|
||||
|
|
|
@ -291,15 +291,15 @@ public:
|
|||
size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) override {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
size_t Tell() const override {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
||||
void Flush() override {
|
||||
// not implemented
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ For details, see http://sourceforge.net/projects/libb64
|
|||
|
||||
#include "cencode.h" // changed from <B64/cencode.h>
|
||||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
static const int CHARS_PER_LINE = 72;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
Flag_WriteSpecialFloats = 0x2,
|
||||
Flag_SkipWhitespaces = 0x4
|
||||
};
|
||||
|
||||
|
||||
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
|
||||
out(out), indent (""), newline("\n"), space(" "), buff (), first(false), flags(flags) {
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
|
@ -499,18 +499,18 @@ static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
|
|||
}
|
||||
break;
|
||||
|
||||
case aiPTI_String:
|
||||
case aiPTI_String:
|
||||
{
|
||||
aiString s;
|
||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||
out.SimpleValue(s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case aiPTI_Buffer:
|
||||
case aiPTI_Buffer:
|
||||
{
|
||||
// binary data is written as series of hex-encoded octets
|
||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
|
|
|
@ -150,7 +150,7 @@ AI_WONT_RETURN void B3DImporter::Fail(const string &str) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int B3DImporter::ReadByte() {
|
||||
if (_pos > _buf.size()) {
|
||||
if (_pos >= _buf.size()) {
|
||||
Fail("EOF");
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,6 @@ void B3DImporter::ReadTRIS(int v0) {
|
|||
ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
|
||||
#endif
|
||||
Fail("Bad triangle index");
|
||||
continue;
|
||||
}
|
||||
face->mNumIndices = 3;
|
||||
face->mIndices = new unsigned[3];
|
||||
|
|
|
@ -52,8 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
template <>
|
||||
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
|
||||
static auto prefix = "BLEND_BMESH: ";
|
||||
return prefix;
|
||||
return "BLEND_BMESH: ";
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
|
|
|
@ -96,7 +96,8 @@ struct CustomDataTypeDescription {
|
|||
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
|
||||
* use a special readfunction for that cases
|
||||
*/
|
||||
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
|
||||
static std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { {
|
||||
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
|
||||
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
|
||||
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
|
||||
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
|
||||
|
|
|
@ -106,9 +106,7 @@ struct ElemBase {
|
|||
// empty
|
||||
}
|
||||
|
||||
virtual ~ElemBase() {
|
||||
// empty
|
||||
}
|
||||
virtual ~ElemBase() = default;
|
||||
|
||||
/** Type name of the element. The type
|
||||
* string points is the `c_str` of the `name` attribute of the
|
||||
|
|
|
@ -80,8 +80,7 @@ namespace Assimp {
|
|||
|
||||
template <>
|
||||
const char *LogFunctions<BlenderImporter>::Prefix() {
|
||||
static auto prefix = "BLEND: ";
|
||||
return prefix;
|
||||
return "BLEND: ";
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
@ -116,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
|
|||
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.
|
||||
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||
// note: this won't catch compressed files
|
||||
static const char *tokens[] = { "<BLENDER", "blender" };
|
||||
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
||||
return ParseMagicToken(pFile, pIOHandler).error.empty();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -143,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
|
|||
// Imports the given file into the given scene structure.
|
||||
void BlenderImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||
std::vector<char> uncompressed;
|
||||
#endif
|
||||
|
||||
FileDatabase file;
|
||||
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
|
||||
if (!streamOrError.error.empty()) {
|
||||
ThrowException(streamOrError.error);
|
||||
}
|
||||
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
|
||||
|
||||
char magic[8] = { 0 };
|
||||
stream->Read(magic, 7, 1);
|
||||
if (strcmp(magic, Tokens[0])) {
|
||||
// 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");
|
||||
}
|
||||
char version[4] = { 0 };
|
||||
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
|
||||
file.little = (stream->Read(version, 1, 1), version[0] == 'v');
|
||||
|
||||
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
||||
if (magic[2] != 8) {
|
||||
ThrowException("Unsupported GZIP compression method");
|
||||
}
|
||||
stream->Read(version, 3, 1);
|
||||
version[3] = '\0';
|
||||
|
||||
// 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;
|
||||
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,
|
||||
LogInfo("Blender version is ", version[0], ".", version + 1,
|
||||
" (64bit: ", file.i64bit ? "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();
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -180,6 +180,19 @@ private:
|
|||
const Blender::MTex *tex,
|
||||
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.
|
||||
// --------------------
|
||||
static void CheckActualType(const Blender::ElemBase *dt,
|
||||
|
|
|
@ -62,9 +62,7 @@ public:
|
|||
/**
|
||||
* The class destructor, virtual.
|
||||
*/
|
||||
virtual ~BlenderModifier() {
|
||||
// empty
|
||||
}
|
||||
virtual ~BlenderModifier() = default;
|
||||
|
||||
// --------------------
|
||||
/**
|
||||
|
|
|
@ -569,7 +569,7 @@ void Structure ::Convert<MVert>(
|
|||
const FileDatabase &db) const {
|
||||
|
||||
ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
|
||||
ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db);
|
||||
ReadFieldArray<ErrorPolicy_Warn>(dest.no, "no", db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
|
||||
//ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
|
||||
|
|
|
@ -182,7 +182,7 @@ struct MVert : ElemBase {
|
|||
int bweight;
|
||||
|
||||
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
|
||||
|
||||
CustomDataLayer() :
|
||||
ElemBase(),
|
||||
type(0),
|
||||
offset(0),
|
||||
flag(0),
|
||||
|
@ -729,7 +728,7 @@ struct Object : ElemBase {
|
|||
ListBase modifiers;
|
||||
|
||||
Object() :
|
||||
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
|
||||
type(Type_EMPTY), parent(nullptr) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -741,8 +740,7 @@ struct Base : ElemBase {
|
|||
std::shared_ptr<Object> object WARN;
|
||||
|
||||
Base() :
|
||||
ElemBase(), prev(nullptr), next(), object() {
|
||||
// empty
|
||||
prev(nullptr) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -758,10 +756,7 @@ struct Scene : ElemBase {
|
|||
|
||||
ListBase base;
|
||||
|
||||
Scene() :
|
||||
ElemBase(), camera(), world(), basact(), master_collection() {
|
||||
// empty
|
||||
}
|
||||
Scene() = default;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -791,10 +786,7 @@ struct Image : ElemBase {
|
|||
|
||||
short gen_x, gen_y, gen_type;
|
||||
|
||||
Image() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
Image() = default;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -884,7 +876,7 @@ struct Tex : ElemBase {
|
|||
//char use_nodes;
|
||||
|
||||
Tex() :
|
||||
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
|
||||
imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
@ -976,10 +968,7 @@ struct MTex : ElemBase {
|
|||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
|
||||
MTex() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
MTex() = default;
|
||||
};
|
||||
|
||||
} // namespace Blender
|
||||
|
|
|
@ -62,8 +62,7 @@ namspace Assimp
|
|||
{
|
||||
template< > const char* LogFunctions< BlenderTessellatorGL >::Prefix()
|
||||
{
|
||||
static auto prefix = "BLEND_TESS_GL: ";
|
||||
return prefix;
|
||||
return "BLEND_TESS_GL: ";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -259,8 +256,7 @@ namespace Assimp
|
|||
{
|
||||
template< > const char* LogFunctions< BlenderTessellatorP2T >::Prefix()
|
||||
{
|
||||
static auto prefix = "BLEND_TESS_P2T: ";
|
||||
return prefix;
|
||||
return "BLEND_TESS_P2T: ";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,8 +86,7 @@ void GetWriterInfo(int &id, String &appname) {
|
|||
|
||||
namespace Assimp {
|
||||
template<> const char* LogFunctions<C4DImporter>::Prefix() {
|
||||
static auto prefix = "C4D: ";
|
||||
return prefix;
|
||||
return "C4D: ";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,15 +105,10 @@ static const aiImporterDesc desc = {
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
C4DImporter::C4DImporter()
|
||||
: BaseImporter() {
|
||||
// empty
|
||||
}
|
||||
C4DImporter::C4DImporter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
C4DImporter::~C4DImporter() {
|
||||
// empty
|
||||
}
|
||||
C4DImporter::~C4DImporter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {
|
||||
|
@ -124,7 +118,7 @@ bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, b
|
|||
} else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -448,7 +448,7 @@ void ColladaExporter::WriteLight(size_t pIndex) {
|
|||
PushTag();
|
||||
switch (light->mType) {
|
||||
case aiLightSource_AMBIENT:
|
||||
WriteAmbienttLight(light);
|
||||
WriteAmbientLight(light);
|
||||
break;
|
||||
case aiLightSource_DIRECTIONAL:
|
||||
WriteDirectionalLight(light);
|
||||
|
@ -543,7 +543,7 @@ void ColladaExporter::WriteSpotLight(const aiLight *const light) {
|
|||
mOutput << startstr << "</spot>" << endstr;
|
||||
}
|
||||
|
||||
void ColladaExporter::WriteAmbienttLight(const aiLight *const light) {
|
||||
void ColladaExporter::WriteAmbientLight(const aiLight *const light) {
|
||||
|
||||
const aiColor3D &color = light->mColorAmbient;
|
||||
mOutput << startstr << "<ambient>" << endstr;
|
||||
|
|
|
@ -101,7 +101,7 @@ protected:
|
|||
void WritePointLight(const aiLight *const light);
|
||||
void WriteDirectionalLight(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
|
||||
void WriteControllerLibrary();
|
||||
|
|
|
@ -666,7 +666,7 @@ struct ChannelEntry {
|
|||
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to 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::Data *mValueData; ///> Source datat array for the key value values
|
||||
const Collada::Data *mValueData; ///> Source data array for the key value values
|
||||
|
||||
ChannelEntry() :
|
||||
mChannel(),
|
||||
|
|
|
@ -92,18 +92,10 @@ inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ColladaLoader::ColladaLoader() :
|
||||
mFileName(),
|
||||
mMeshIndexByID(),
|
||||
mMaterialIndexByName(),
|
||||
mMeshes(),
|
||||
newMats(),
|
||||
mCameras(),
|
||||
mLights(),
|
||||
mTextures(),
|
||||
mAnims(),
|
||||
noSkeletonMesh(false),
|
||||
removeEmptyBones(false),
|
||||
ignoreUpDirection(false),
|
||||
ignoreUnitSize(false),
|
||||
useColladaName(false),
|
||||
mNodeNameCounter(0) {
|
||||
// empty
|
||||
|
@ -131,6 +123,7 @@ void ColladaLoader::SetupProperties(const Importer *pImp) {
|
|||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||
removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 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;
|
||||
}
|
||||
|
||||
|
@ -179,12 +172,15 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
|||
// ... then fill the materials with the now adjusted settings
|
||||
FillMaterials(parser, pScene);
|
||||
|
||||
// Apply unit-size scale calculation
|
||||
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
|
||||
0, parser.mUnitSize, 0, 0,
|
||||
0, 0, parser.mUnitSize, 0,
|
||||
0, 0, 0, 1);
|
||||
if (!ignoreUnitSize) {
|
||||
// Apply unit-size scale calculation
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
parser.mUnitSize, 0, 0, 0,
|
||||
0, parser.mUnitSize, 0, 0,
|
||||
0, 0, parser.mUnitSize, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
if (!ignoreUpDirection) {
|
||||
// Convert to Y_UP, if different orientation
|
||||
if (parser.mUpDirection == ColladaParser::UP_X) {
|
||||
|
@ -1523,7 +1519,7 @@ void ColladaLoader::AddTexture(aiMaterial &mat,
|
|||
map = -1;
|
||||
for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
|
||||
if (IsNumeric(*it)) {
|
||||
map = strtoul10(&(*it));
|
||||
map = strtoul10(&(*it));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,6 +239,7 @@ protected:
|
|||
bool noSkeletonMesh;
|
||||
bool removeEmptyBones;
|
||||
bool ignoreUpDirection;
|
||||
bool ignoreUnitSize;
|
||||
bool useColladaName;
|
||||
|
||||
/** Used by FindNameForNode() to generate unique node names */
|
||||
|
|
|
@ -762,6 +762,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
|||
if (text == nullptr) {
|
||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||
}
|
||||
SkipSpacesAndLineEnd(&text);
|
||||
it->first = strtoul10(text, &text);
|
||||
SkipSpacesAndLineEnd(&text);
|
||||
if (*text == 0) {
|
||||
|
@ -1854,7 +1855,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
|||
default:
|
||||
// LineStrip is not supported due to expected index unmangling
|
||||
throw DeadlyImportError("Unsupported primitive type.");
|
||||
break;
|
||||
}
|
||||
|
||||
// store the face size to later reconstruct the face from
|
||||
|
|
|
@ -65,7 +65,6 @@ public:
|
|||
LineReader(StreamReaderLE& reader)
|
||||
: splitter(reader,false,true)
|
||||
, groupcode( 0 )
|
||||
, value()
|
||||
, end() {
|
||||
// empty
|
||||
}
|
||||
|
@ -186,8 +185,7 @@ struct InsertBlock {
|
|||
InsertBlock()
|
||||
: pos()
|
||||
, scale(1.f,1.f,1.f)
|
||||
, angle()
|
||||
, name() {
|
||||
, angle() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
// taken directly from the DXF spec.
|
||||
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 (0.0f, 1.0f, 0.0f, 1.0f), // green
|
||||
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 (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_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC"
|
||||
|
||||
|
@ -109,14 +110,6 @@ static const aiImporterDesc desc = {
|
|||
"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.
|
||||
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);
|
||||
}
|
||||
|
||||
if (! output.blocks.size() ) {
|
||||
if (output.blocks.empty()) {
|
||||
throw DeadlyImportError("DXF: no data blocks loaded");
|
||||
}
|
||||
|
||||
|
@ -371,7 +364,7 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
|
|||
ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<DXF::PolyLine> pl_out = std::shared_ptr<DXF::PolyLine>(new DXF::PolyLine(*pl_in));
|
||||
|
||||
if (bl_src.base.Length() || insert.scale.x!=1.f || insert.scale.y!=1.f || insert.scale.z!=1.f || insert.angle || insert.pos.Length()) {
|
||||
|
@ -587,10 +580,11 @@ void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output)
|
|||
}
|
||||
}
|
||||
|
||||
#define DXF_POLYLINE_FLAG_CLOSED 0x1
|
||||
#define DXF_POLYLINE_FLAG_3D_POLYLINE 0x8
|
||||
#define DXF_POLYLINE_FLAG_3D_POLYMESH 0x10
|
||||
#define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40
|
||||
static constexpr unsigned int DXF_POLYLINE_FLAG_CLOSED = 0x1;
|
||||
// Currently unused
|
||||
//static constexpr unsigned int DXF_POLYLINE_FLAG_3D_POLYLINE = 0x8;
|
||||
//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) {
|
||||
|
@ -639,12 +633,6 @@ void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output)
|
|||
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) {
|
||||
ASSIMP_LOG_WARN("DXF: unexpected vertex count in polymesh: ",
|
||||
line.positions.size(),", expected ", vguess );
|
||||
|
@ -734,12 +722,18 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
|
|||
case 71:
|
||||
case 72:
|
||||
case 73:
|
||||
case 74:
|
||||
if (cnti == 4) {
|
||||
ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
|
||||
break;
|
||||
case 74: {
|
||||
if (cnti == 4) {
|
||||
ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
|
||||
break;
|
||||
}
|
||||
const int index = reader.ValueAsSignedInt();
|
||||
if (index >= 0) {
|
||||
indices[cnti++] = static_cast<unsigned int>(index);
|
||||
} else {
|
||||
indices[cnti++] = static_cast<unsigned int>(-index);
|
||||
}
|
||||
}
|
||||
indices[cnti++] = reader.ValueAsUnsignedInt();
|
||||
break;
|
||||
|
||||
// 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
|
||||
// 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) {
|
||||
break;
|
||||
}
|
||||
switch (reader.GroupCode())
|
||||
{
|
||||
switch (reader.GroupCode()) {
|
||||
|
||||
// 8 specifies the layer
|
||||
case 8:
|
||||
|
|
|
@ -68,8 +68,8 @@ namespace DXF {
|
|||
*/
|
||||
class DXFImporter : public BaseImporter {
|
||||
public:
|
||||
DXFImporter();
|
||||
~DXFImporter() override;
|
||||
DXFImporter() = default;
|
||||
~DXFImporter() override = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given 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) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
@ -341,8 +342,7 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input,
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits)
|
||||
{
|
||||
bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
|
@ -408,7 +408,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while(Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
|
@ -431,8 +431,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||
{
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
|
||||
ai_assert(input);
|
||||
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
|
||||
|
||||
|
@ -465,7 +464,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
|||
try
|
||||
{
|
||||
while (cursor < end ) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
|
||||
if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}; // 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 MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||
|
|
|
@ -93,6 +93,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
|
|||
mSceneOut(out),
|
||||
doc(doc),
|
||||
mRemoveEmptyBones(removeEmptyBones) {
|
||||
|
||||
|
||||
// animations need to be converted first since this will
|
||||
// populate the node_anim_chain_bits map, which is needed
|
||||
// to determine which nodes need to be generated.
|
||||
|
@ -421,16 +423,32 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
|
|||
|
||||
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
||||
|
||||
// NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
|
||||
// All transformations to the camera will be handled by its node in the scenegraph.
|
||||
out_camera->mPosition = aiVector3D(0.0f);
|
||||
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
|
||||
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
|
||||
|
||||
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();
|
||||
out_camera->mClipPlaneFar = cam.FarPlane();
|
||||
// TODO: This is not a complete solution for how FBX cameras can be stored.
|
||||
// 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->mClipPlaneFar = cam.FarPlane();
|
||||
}
|
||||
|
@ -640,7 +658,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
|
|||
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
|
||||
const PropertyTable &props = model.Props();
|
||||
|
||||
const auto zero_epsilon = ai_epsilon;
|
||||
const auto zero_epsilon = Math::getEpsilon<ai_real>();
|
||||
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
|
||||
const TransformationComp comp = static_cast<TransformationComp>(i);
|
||||
|
@ -873,8 +891,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
|
|||
data->Set(index++, prop.first, interpretedBool->Value());
|
||||
} else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
|
||||
data->Set(index++, prop.first, interpretedInt->Value());
|
||||
} else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedUInt->Value());
|
||||
} else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedUint64->Value());
|
||||
} else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
|
||||
data->Set(index++, prop.first, interpretedint64->Value());
|
||||
} else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
|
||||
data->Set(index++, prop.first, interpretedFloat->Value());
|
||||
} else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
|
||||
|
@ -1176,15 +1198,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
|
|||
std::vector<aiAnimMesh *> animMeshes;
|
||||
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
|
||||
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
|
||||
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (size_t i = 0; i < shapeGeometries.size(); i++) {
|
||||
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
|
||||
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
|
||||
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
|
||||
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
|
||||
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
|
||||
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
|
||||
const auto &curVertices = shapeGeometry->GetVertices();
|
||||
const auto &curNormals = shapeGeometry->GetNormals();
|
||||
const auto &curIndices = shapeGeometry->GetIndices();
|
||||
//losing channel name if using shapeGeometry->Name()
|
||||
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name()));
|
||||
// if blendShapeChannel Name is empty or don't have a ".", add geoMetryName;
|
||||
auto aniName = FixAnimMeshName(blendShapeChannel->Name());
|
||||
auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
|
||||
if (aniName.empty()) {
|
||||
aniName = geoMetryName;
|
||||
}
|
||||
else if (aniName.find('.') == aniName.npos) {
|
||||
aniName += "." + geoMetryName;
|
||||
}
|
||||
animMesh->mName.Set(aniName);
|
||||
for (size_t j = 0; j < curIndices.size(); j++) {
|
||||
const unsigned int curIndex = curIndices.at(j);
|
||||
aiVector3D vertex = curVertices.at(j);
|
||||
|
@ -1406,13 +1436,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
|||
std::vector<aiAnimMesh *> animMeshes;
|
||||
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
|
||||
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
|
||||
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (size_t i = 0; i < shapeGeometries.size(); i++) {
|
||||
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
|
||||
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
|
||||
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
|
||||
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
|
||||
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
|
||||
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
|
||||
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
|
||||
const auto& curVertices = shapeGeometry->GetVertices();
|
||||
const auto& curNormals = shapeGeometry->GetNormals();
|
||||
const auto& curIndices = shapeGeometry->GetIndices();
|
||||
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
|
||||
for (size_t j = 0; j < curIndices.size(); j++) {
|
||||
unsigned int curIndex = curIndices.at(j);
|
||||
|
@ -1455,7 +1484,9 @@ static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *s
|
|||
skeletonBone->mWeights = bone->mWeights;
|
||||
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
|
||||
skeletonBone->mMeshId = mesh;
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
skeletonBone->mNode = bone->mNode;
|
||||
#endif
|
||||
skeletonBone->mParent = -1;
|
||||
}
|
||||
|
||||
|
@ -1563,7 +1594,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
|
|||
out->mBones = nullptr;
|
||||
out->mNumBones = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out->mBones = new aiBone *[bones.size()]();
|
||||
out->mNumBones = static_cast<unsigned int>(bones.size());
|
||||
|
@ -3228,7 +3259,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
|
|||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
|
||||
const auto zero_epsilon = ai_epsilon;
|
||||
|
||||
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
|
||||
|
|
|
@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
|
|||
for (const Connection* con : conns) {
|
||||
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
auto pr = blendShapeChannels.insert(bspc);
|
||||
if (!pr.second) {
|
||||
FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,8 +181,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
|
|||
for (const Connection* con : conns) {
|
||||
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
auto pr = shapeGeometries.insert(sg);
|
||||
if (!pr.second) {
|
||||
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser& parser, const ImportSettings& settings) :
|
||||
Document::Document(Parser& parser, const ImportSettings& settings) :
|
||||
settings(settings), parser(parser) {
|
||||
ASSIMP_LOG_DEBUG("Creating FBX Document");
|
||||
|
||||
|
@ -265,13 +265,17 @@ Document::Document(const Parser& parser, const ImportSettings& settings) :
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document() {
|
||||
for(ObjectMap::value_type& v : objects) {
|
||||
delete v.second;
|
||||
Document::~Document()
|
||||
{
|
||||
// The document does not own the memory for the following objects, but we need to call their d'tor
|
||||
// so they can properly free memory like string members:
|
||||
|
||||
for (ObjectMap::value_type &v : objects) {
|
||||
delete_LazyObject(v.second);
|
||||
}
|
||||
|
||||
for(ConnectionMap::value_type& v : src_connections) {
|
||||
delete v.second;
|
||||
for (ConnectionMap::value_type &v : src_connections) {
|
||||
delete_Connection(v.second);
|
||||
}
|
||||
// |dest_connections| contain the same Connection objects as the |src_connections|
|
||||
}
|
||||
|
@ -356,9 +360,11 @@ void Document::ReadObjects() {
|
|||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, *eobjects, *this);
|
||||
objects[0] = new_LazyObject(0L, *eobjects, *this);
|
||||
|
||||
const Scope& sobjects = *eobjects->Compound();
|
||||
for(const ElementMap::value_type& el : sobjects.Elements()) {
|
||||
|
@ -381,11 +387,13 @@ void Document::ReadObjects() {
|
|||
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);
|
||||
delete foundObject->second;
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, *el.second, *this);
|
||||
objects[id] = new_LazyObject(id, *el.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if(!strcmp(el.first.c_str(),"AnimationStack")) {
|
||||
|
@ -452,8 +460,10 @@ void Document::ReadPropertyTemplates() {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections() {
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
void Document::ReadConnections()
|
||||
{
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
const Scope &sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
if(!econns || !econns->Compound()) {
|
||||
|
@ -492,7 +502,7 @@ void Document::ReadConnections() {
|
|||
}
|
||||
|
||||
// add new connection
|
||||
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
|
||||
const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
|
||||
src_connections.insert(ConnectionMap::value_type(src,c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest,c));
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_DOCUMENT_H
|
||||
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
#include <stdint.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include "FBXProperties.h"
|
||||
|
@ -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) _AI_CONCAT(a,b)
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
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 Object;
|
||||
struct ImportSettings;
|
||||
|
@ -80,6 +86,10 @@ class BlendShape;
|
|||
class Skin;
|
||||
class Cluster;
|
||||
|
||||
#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
|
||||
#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
|
||||
#define delete_LazyObject(_p) (_p)->~LazyObject()
|
||||
#define delete_Connection(_p) (_p)->~Connection()
|
||||
|
||||
/** Represents a delay-parsed FBX objects. Many objects in the scene
|
||||
* are not needed by assimp, so it makes no sense to parse them
|
||||
|
@ -242,7 +252,7 @@ public:
|
|||
fbx_simple_property(FilmAspectRatio, float, 1.0f)
|
||||
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)
|
||||
};
|
||||
|
||||
|
@ -855,14 +865,14 @@ public:
|
|||
return fullWeights;
|
||||
}
|
||||
|
||||
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const {
|
||||
const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
|
||||
return shapeGeometries;
|
||||
}
|
||||
|
||||
private:
|
||||
float percent;
|
||||
WeightArray fullWeights;
|
||||
std::vector<const ShapeGeometry*> shapeGeometries;
|
||||
std::unordered_set<const ShapeGeometry*> shapeGeometries;
|
||||
};
|
||||
|
||||
/** DOM class for BlendShape deformers */
|
||||
|
@ -872,12 +882,12 @@ public:
|
|||
|
||||
virtual ~BlendShape();
|
||||
|
||||
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const {
|
||||
const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
|
||||
return blendShapeChannels;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const BlendShapeChannel*> blendShapeChannels;
|
||||
std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
|
||||
};
|
||||
|
||||
/** DOM class for skin deformer clusters (aka sub-deformers) */
|
||||
|
@ -1072,7 +1082,7 @@ private:
|
|||
/** DOM root for a FBX file */
|
||||
class Document {
|
||||
public:
|
||||
Document(const Parser& parser, const ImportSettings& settings);
|
||||
Document(Parser& parser, const ImportSettings& settings);
|
||||
|
||||
~Document();
|
||||
|
||||
|
@ -1156,7 +1166,7 @@ private:
|
|||
const ImportSettings& settings;
|
||||
|
||||
ObjectMap objects;
|
||||
const Parser& parser;
|
||||
Parser& parser;
|
||||
|
||||
PropertyTemplateMap templates;
|
||||
ConnectionMap src_connections;
|
||||
|
|
|
@ -360,7 +360,7 @@ void FBX::Node::EndBinary(
|
|||
bool has_children
|
||||
) {
|
||||
// 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
|
||||
this->end_pos = s.Tell();
|
||||
|
|
|
@ -77,8 +77,6 @@ public: // constructors
|
|||
/// The class constructor with the name.
|
||||
Node(const std::string& n)
|
||||
: name(n)
|
||||
, properties()
|
||||
, children()
|
||||
, force_has_children( false ) {
|
||||
// empty
|
||||
}
|
||||
|
@ -87,8 +85,6 @@ public: // constructors
|
|||
template <typename... More>
|
||||
Node(const std::string& n, More&&... more)
|
||||
: name(n)
|
||||
, properties()
|
||||
, children()
|
||||
, force_has_children(false) {
|
||||
AddProperties(std::forward<More>(more)...);
|
||||
}
|
||||
|
|
|
@ -62,8 +62,7 @@ namespace Assimp {
|
|||
|
||||
template <>
|
||||
const char *LogFunctions<FBXImporter>::Prefix() {
|
||||
static auto prefix = "FBX: ";
|
||||
return prefix;
|
||||
return "FBX: ";
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
@ -90,10 +89,7 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by #Importer
|
||||
FBXImporter::FBXImporter() :
|
||||
mSettings() {
|
||||
// empty
|
||||
}
|
||||
FBXImporter::FBXImporter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
||||
Assimp::StackAllocator tempAllocator;
|
||||
try {
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens, begin, contents.size());
|
||||
TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
|
||||
} else {
|
||||
Tokenize(tokens, begin);
|
||||
Tokenize(tokens, begin, tempAllocator);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
Parser parser(tokens, tempAllocator, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser, mSettings);
|
||||
|
@ -187,10 +183,12 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
// assimp universal format (M)
|
||||
SetFileScale(size_relative_to_cm * 0.01f);
|
||||
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
throw;
|
||||
// This collection does not own the memory for the tokens, but we need to call their d'tor
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
|
||||
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,20 +138,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material() = default;
|
||||
|
||||
aiVector2D uvTrans;
|
||||
aiVector2D uvScaling;
|
||||
ai_real uvRotation;
|
||||
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
std::string fileName;
|
||||
std::string alphaSource;
|
||||
std::shared_ptr<const PropertyTable> props;
|
||||
|
||||
unsigned int crop[4]{};
|
||||
|
||||
const Video* media;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
|
||||
Object(id,element,name),
|
||||
|
|
|
@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
|
|||
}
|
||||
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
|
||||
if (bsp) {
|
||||
blendShapes.push_back(bsp);
|
||||
auto pr = blendShapes.insert(bsp);
|
||||
if (!pr.second) {
|
||||
FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
|
||||
const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
Copyright (c) 2006-2023, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
@ -53,84 +52,101 @@ namespace Assimp {
|
|||
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 {
|
||||
public:
|
||||
/// @brief The class constructor with all parameters.
|
||||
/// @param id The id.
|
||||
/// @param element
|
||||
/// @param name
|
||||
/// @param doc
|
||||
/// @param element The element instance
|
||||
/// @param name The name instance
|
||||
/// @param doc The document instance
|
||||
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||
|
||||
/// @brief The class destructor, default.
|
||||
virtual ~Geometry() = default;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Get the BlendShape attached to this geometry or nullptr
|
||||
const std::vector<const BlendShape*>& GetBlendShapes() const;
|
||||
/// @brief Get the BlendShape attached to this geometry or nullptr
|
||||
/// @return The blendshape arrays.
|
||||
const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
|
||||
|
||||
private:
|
||||
const Skin* skin;
|
||||
std::vector<const BlendShape*> blendShapes;
|
||||
std::unordered_set<const BlendShape*> blendShapes;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
||||
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Mesh"
|
||||
* @brief DOM class for FBX geometry of type "Mesh"
|
||||
*/
|
||||
class MeshGeometry : public Geometry {
|
||||
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 );
|
||||
|
||||
/** The class destructor */
|
||||
/// @brief The class destructor, 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;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
/// @brief Get a vector of all vertex normals or an empty array if no normals are specified.
|
||||
/// @return The normal vector.
|
||||
const std::vector<aiVector3D>& GetNormals() const;
|
||||
|
||||
/** Get a list of all vertex tangents or an empty array
|
||||
* if no tangents are specified */
|
||||
/// @brief Get a vector of all vertex tangents or an empty array if no tangents are specified.
|
||||
/// @return The vertex tangents vector.
|
||||
const std::vector<aiVector3D>& GetTangents() const;
|
||||
|
||||
/** Get a list of all vertex bi-normals or an empty array
|
||||
* if no bi-normals are specified */
|
||||
/// @brief Get a vector of all vertex bi-normals or an empty array if no bi-normals are specified.
|
||||
/// @return The binomal vector.
|
||||
const std::vector<aiVector3D>& GetBinormals() const;
|
||||
|
||||
/** Return list of faces - each entry denotes a face and specifies
|
||||
* how many vertices it has. Vertices are taken from the
|
||||
* vertex data arrays in sequential order. */
|
||||
/// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
|
||||
/// Vertices are taken from the vertex data arrays in sequential order.
|
||||
/// @return The face indices vector.
|
||||
const std::vector<unsigned int>& GetFaceIndexCounts() const;
|
||||
|
||||
/** Get a UV coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
/// @brief Get a UV coordinate slot, returns an empty array if 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;
|
||||
|
||||
/** Get a UV coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
/// @brief Get a UV coordinate slot, returns an empty array if 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;
|
||||
|
||||
/** Get a vertex color coordinate slot, returns an empty array if
|
||||
* the requested slot does not exist. */
|
||||
/// @brief Get a vertex color coordinate slot, returns an empty array if 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;
|
||||
|
||||
/** Get per-face-vertex material assignments */
|
||||
/// @brief Get per-face-vertex material assignments.
|
||||
/// @return The Material indices Array.
|
||||
const MatIndexArray& GetMaterialIndices() const;
|
||||
|
||||
/** Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr
|
||||
* if the vertex index is not valid. */
|
||||
/// @brief Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr 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;
|
||||
|
||||
/** Determine the face to which a particular output vertex index belongs.
|
||||
* This mapping is always unique. */
|
||||
/// @brief Determine the face to which a particular output vertex index belongs.
|
||||
/// 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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -88,6 +88,7 @@ namespace {
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_WONT_RETURN void ParseError(const std::string& message, TokenPtr token) AI_WONT_RETURN_SUFFIX;
|
||||
void ParseError(const std::string& message, TokenPtr token)
|
||||
{
|
||||
if(token) {
|
||||
|
@ -115,8 +116,11 @@ namespace Assimp {
|
|||
namespace FBX {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
|
||||
Element::Element(const Token& key_token, Parser& parser) :
|
||||
key_token(key_token), compound(nullptr)
|
||||
{
|
||||
TokenPtr n = nullptr;
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
do {
|
||||
n = parser.AdvanceToNextToken();
|
||||
if(!n) {
|
||||
|
@ -145,7 +149,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
|
|||
}
|
||||
|
||||
if (n->Type() == TokenType_OPEN_BRACKET) {
|
||||
compound.reset(new Scope(parser));
|
||||
compound = new_Scope(parser);
|
||||
|
||||
// current token should be a TOK_CLOSE_BRACKET
|
||||
n = parser.CurrentToken();
|
||||
|
@ -163,6 +167,15 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
if (compound) {
|
||||
delete_Scope(compound);
|
||||
}
|
||||
|
||||
// no need to delete tokens, they are owned by the parser
|
||||
}
|
||||
|
||||
Scope::Scope(Parser& parser,bool topLevel)
|
||||
{
|
||||
if(!topLevel) {
|
||||
|
@ -172,6 +185,7 @@ Scope::Scope(Parser& parser,bool topLevel)
|
|||
}
|
||||
}
|
||||
|
||||
StackAllocator &allocator = parser.GetAllocator();
|
||||
TokenPtr n = parser.AdvanceToNextToken();
|
||||
if (n == nullptr) {
|
||||
ParseError("unexpected end of file");
|
||||
|
@ -187,37 +201,46 @@ Scope::Scope(Parser& parser,bool topLevel)
|
|||
if (str.empty()) {
|
||||
ParseError("unexpected content: empty string.");
|
||||
}
|
||||
|
||||
elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
|
||||
|
||||
auto *element = new_Element(*n, parser);
|
||||
|
||||
// Element() should stop at the next Key token (or right after a Close token)
|
||||
n = parser.CurrentToken();
|
||||
if (n == nullptr) {
|
||||
if (topLevel) {
|
||||
elements.insert(ElementMap::value_type(str, element));
|
||||
return;
|
||||
}
|
||||
delete_Element(element);
|
||||
ParseError("unexpected end of file",parser.LastToken());
|
||||
} else {
|
||||
elements.insert(ElementMap::value_type(str, element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Scope::~Scope() {
|
||||
for(ElementMap::value_type& v : elements) {
|
||||
delete v.second;
|
||||
Scope::~Scope()
|
||||
{
|
||||
// This collection does not own the memory for the elements, but we need to call their d'tor:
|
||||
|
||||
for (ElementMap::value_type &v : elements) {
|
||||
delete_Element(v.second);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parser::Parser (const TokenList& tokens, bool is_binary)
|
||||
: tokens(tokens)
|
||||
, last()
|
||||
, current()
|
||||
, cursor(tokens.begin())
|
||||
, is_binary(is_binary)
|
||||
Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
|
||||
tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("Parsing FBX tokens");
|
||||
root.reset(new Scope(*this,true));
|
||||
root = new_Scope(*this, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parser::~Parser()
|
||||
{
|
||||
delete_Scope(root);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/LogAux.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
|
||||
#include "Common/StackAllocator.h"
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
|
@ -63,14 +64,14 @@ class Parser;
|
|||
class Element;
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef std::vector< Scope* > ScopeList;
|
||||
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
|
||||
|
||||
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
# define new_Scope new Scope
|
||||
# define new_Element new Element
|
||||
using ScopeList = std::vector<Scope*>;
|
||||
using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
|
||||
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
|
||||
|
||||
#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
|
||||
#define new_Element new (allocator.Allocate(sizeof(Element))) Element
|
||||
#define delete_Scope(_p) (_p)->~Scope()
|
||||
#define delete_Element(_p) (_p)->~Element()
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
|
@ -82,15 +83,16 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
|
|||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
* as their trailing member.
|
||||
**/
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Element(const Token& key_token, Parser& parser);
|
||||
~Element() = default;
|
||||
~Element();
|
||||
|
||||
const Scope* Compound() const {
|
||||
return compound.get();
|
||||
return compound;
|
||||
}
|
||||
|
||||
const Token& KeyToken() const {
|
||||
|
@ -104,7 +106,7 @@ public:
|
|||
private:
|
||||
const Token& key_token;
|
||||
TokenList tokens;
|
||||
std::unique_ptr<Scope> compound;
|
||||
Scope* compound;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
|
@ -159,8 +161,8 @@ class Parser
|
|||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser (const TokenList& tokens,bool is_binary);
|
||||
~Parser() = default;
|
||||
Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary);
|
||||
~Parser();
|
||||
|
||||
const Scope& GetRootScope() const {
|
||||
return *root;
|
||||
|
@ -170,6 +172,10 @@ public:
|
|||
return is_binary;
|
||||
}
|
||||
|
||||
StackAllocator &GetAllocator() {
|
||||
return allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
@ -180,10 +186,10 @@ private:
|
|||
|
||||
private:
|
||||
const TokenList& tokens;
|
||||
|
||||
StackAllocator &allocator;
|
||||
TokenPtr last, current;
|
||||
TokenList::const_iterator cursor;
|
||||
std::unique_ptr<Scope> root;
|
||||
Scope *root;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
|
|
@ -94,7 +94,8 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line,
|
|||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end,
|
||||
void ProcessDataToken(TokenList &output_tokens, StackAllocator &token_allocator,
|
||||
const char*& start, const char*& end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
|
@ -131,8 +132,7 @@ void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList& output_tokens, const char* input)
|
||||
{
|
||||
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
|
||||
ai_assert(input);
|
||||
ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
|
||||
|
||||
|
@ -164,7 +164,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
in_double_quotes = false;
|
||||
token_end = cur;
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
pending_data_token = false;
|
||||
}
|
||||
continue;
|
||||
|
@ -181,30 +181,30 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
continue;
|
||||
|
||||
case ';':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
comment = true;
|
||||
continue;
|
||||
|
||||
case '{':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end, line, column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
|
||||
continue;
|
||||
|
||||
case ',':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
|
||||
}
|
||||
else {
|
||||
TokenizeError("unexpected colon", line, column);
|
||||
|
@ -226,7 +226,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
|
|||
}
|
||||
}
|
||||
|
||||
ProcessDataToken(output_tokens,token_begin,token_end,line,column,type);
|
||||
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
|
||||
}
|
||||
|
||||
pending_data_token = false;
|
||||
|
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXCompileConfig.h"
|
||||
#include "Common/StackAllocator.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/defs.h>
|
||||
#include <vector>
|
||||
|
@ -154,11 +155,11 @@ private:
|
|||
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 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.
|
||||
|
@ -168,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList;
|
|||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void Tokenize(TokenList& output_tokens, const char* input);
|
||||
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &tokenAllocator);
|
||||
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
|
@ -179,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
|
|||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @throw DeadlyImportError if something goes wrong */
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &tokenAllocator);
|
||||
|
||||
|
||||
} // ! FBX
|
||||
|
|
|
@ -66,6 +66,17 @@ struct delete_fun
|
|||
}
|
||||
};
|
||||
|
||||
/** helper for std::for_each to call the destructor on all items in a container without freeing their heap*/
|
||||
template <typename T>
|
||||
struct destructor_fun {
|
||||
void operator()(const volatile T* del) {
|
||||
if (del) {
|
||||
del->~T();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Get a string representation for a #TokenType. */
|
||||
const char* TokenTypeString(TokenType t);
|
||||
|
||||
|
|
|
@ -115,7 +115,9 @@ void HMPImporter::InternReadFile(const std::string &pFile,
|
|||
throw DeadlyImportError("HMP File is too small.");
|
||||
|
||||
// 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);
|
||||
iFileSize = (unsigned int)fileSize;
|
||||
|
||||
|
@ -143,9 +145,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
|
|||
// Print the magic word to the logger
|
||||
std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic));
|
||||
|
||||
delete[] mBuffer;
|
||||
mBuffer = nullptr;
|
||||
|
||||
// We're definitely unable to load this file
|
||||
throw DeadlyImportError("Unknown HMP subformat ", pFile,
|
||||
". Magic word (", szBuffer, ") is not known");
|
||||
|
@ -153,9 +152,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
|
|||
|
||||
// Set the AI_SCENE_FLAGS_TERRAIN bit
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN;
|
||||
|
||||
delete[] mBuffer;
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -327,7 +323,7 @@ void HMPImporter::CreateMaterial(const unsigned char *szCurrent,
|
|||
ReadFirstSkin(pcHeader->numskins, szCurrent, &szCurrent);
|
||||
*szCurrentOut = szCurrent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// generate a default material
|
||||
const int iMode = (int)aiShadingMode_Gouraud;
|
||||
|
@ -445,11 +441,11 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
|
|||
szCursor += sizeof(uint32_t);
|
||||
|
||||
// allocate an output material
|
||||
aiMaterial *pcMat = new aiMaterial();
|
||||
std::unique_ptr<aiMaterial> pcMat(new aiMaterial());
|
||||
|
||||
// read the skin, this works exactly as for MDL7
|
||||
ParseSkinLump_3DGS_MDL7(szCursor, &szCursor,
|
||||
pcMat, iType, iWidth, iHeight);
|
||||
pcMat.get(), iType, iWidth, iHeight);
|
||||
|
||||
// now we need to skip any other skins ...
|
||||
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 ...
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mMaterials = new aiMaterial *[1];
|
||||
pScene->mMaterials[0] = pcMat;
|
||||
pScene->mMaterials[0] = pcMat.release();
|
||||
|
||||
*szCursorOut = szCursor;
|
||||
}
|
||||
|
@ -484,11 +480,11 @@ void HMPImporter::GenerateTextureCoords(const unsigned int width, const unsigned
|
|||
if (uv == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (height == 0.0f || width == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const float fY = (1.0f / height) + (1.0f / height) / height;
|
||||
const float fX = (1.0f / width) + (1.0f / width) / width;
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Import a HMP4 file
|
||||
*/
|
||||
void InternReadFile_HMP4();
|
||||
AI_WONT_RETURN void InternReadFile_HMP4() AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Import a HMP5 file
|
||||
|
|
|
@ -73,8 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
template <>
|
||||
const char *LogFunctions<IFCImporter>::Prefix() {
|
||||
static auto prefix = "IFC: ";
|
||||
return prefix;
|
||||
return "IFC: ";
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "AssetLib/IFC/IFCUtil.h"
|
||||
#include "Common/PolyTools.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
@ -235,7 +236,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
|
|||
struct CompareVector {
|
||||
bool operator () (const IfcVector3& a, const IfcVector3& b) const {
|
||||
IfcVector3 d = a - b;
|
||||
IfcFloat eps = ai_epsilon;
|
||||
constexpr IfcFloat eps = ai_epsilon;
|
||||
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
|
||||
}
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/anim.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Irr importer class.
|
||||
|
@ -71,13 +71,13 @@ public:
|
|||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
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:
|
||||
const aiImporterDesc* GetInfo () const override;
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
const aiImporterDesc *GetInfo() const override;
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||
void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
private:
|
||||
/** Data structure for a scene-graph node animator
|
||||
|
@ -85,27 +85,19 @@ private:
|
|||
struct Animator {
|
||||
// Type of the animator
|
||||
enum AT {
|
||||
UNKNOWN = 0x0,
|
||||
ROTATION = 0x1,
|
||||
FLY_CIRCLE = 0x2,
|
||||
FLY_STRAIGHT = 0x3,
|
||||
UNKNOWN = 0x0,
|
||||
ROTATION = 0x1,
|
||||
FLY_CIRCLE = 0x2,
|
||||
FLY_STRAIGHT = 0x3,
|
||||
FOLLOW_SPLINE = 0x4,
|
||||
OTHER = 0x5
|
||||
OTHER = 0x5
|
||||
|
||||
} type;
|
||||
|
||||
explicit Animator(AT t = UNKNOWN)
|
||||
: 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)
|
||||
{
|
||||
explicit Animator(AT t = UNKNOWN) :
|
||||
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) {
|
||||
}
|
||||
|
||||
|
||||
// common parameters
|
||||
ai_real speed;
|
||||
aiVector3D direction;
|
||||
|
@ -128,11 +120,9 @@ private:
|
|||
|
||||
/** Data structure for a scene-graph node in an IRR file
|
||||
*/
|
||||
struct Node
|
||||
{
|
||||
struct Node {
|
||||
// Type of the node
|
||||
enum ET
|
||||
{
|
||||
enum ET {
|
||||
LIGHT,
|
||||
CUBE,
|
||||
MESH,
|
||||
|
@ -144,21 +134,20 @@ private:
|
|||
ANIMMESH
|
||||
} type;
|
||||
|
||||
explicit Node(ET t)
|
||||
: type (t)
|
||||
, scaling (1.0,1.0,1.0) // assume uniform scaling by default
|
||||
, parent()
|
||||
, framesPerSecond (0.0)
|
||||
, id()
|
||||
, sphereRadius (1.0)
|
||||
, spherePolyCountX (100)
|
||||
, spherePolyCountY (100)
|
||||
{
|
||||
explicit Node(ET t) :
|
||||
type(t), scaling(1.0, 1.0, 1.0) // assume uniform scaling by default
|
||||
,
|
||||
parent(),
|
||||
framesPerSecond(0.0),
|
||||
id(),
|
||||
sphereRadius(1.0),
|
||||
spherePolyCountX(100),
|
||||
spherePolyCountY(100) {
|
||||
|
||||
// Generate a default name for the node
|
||||
char buffer[128];
|
||||
static int cnt;
|
||||
ai_snprintf(buffer, 128, "IrrNode_%i",cnt++);
|
||||
ai_snprintf(buffer, 128, "IrrNode_%i", cnt++);
|
||||
name = std::string(buffer);
|
||||
|
||||
// reserve space for up to 5 materials
|
||||
|
@ -175,10 +164,10 @@ private:
|
|||
std::string name;
|
||||
|
||||
// List of all child nodes
|
||||
std::vector<Node*> children;
|
||||
std::vector<Node *> children;
|
||||
|
||||
// Parent node
|
||||
Node* parent;
|
||||
Node *parent;
|
||||
|
||||
// Animated meshes: frames per second
|
||||
// 0.f if not specified
|
||||
|
@ -190,13 +179,13 @@ private:
|
|||
|
||||
// Meshes: List of materials to be assigned
|
||||
// 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
|
||||
ai_real sphereRadius;
|
||||
|
||||
// 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
|
||||
std::list<Animator> animators;
|
||||
|
@ -204,40 +193,54 @@ private:
|
|||
|
||||
/** Data structure for a vertex in an IRR skybox
|
||||
*/
|
||||
struct SkyboxVertex
|
||||
{
|
||||
struct SkyboxVertex {
|
||||
SkyboxVertex() = default;
|
||||
|
||||
//! Construction from single vertex components
|
||||
SkyboxVertex(ai_real px, ai_real py, ai_real pz,
|
||||
ai_real nx, ai_real ny, ai_real nz,
|
||||
ai_real uvx, ai_real uvy)
|
||||
ai_real nx, ai_real ny, ai_real nz,
|
||||
ai_real uvx, ai_real uvy)
|
||||
|
||||
: position (px,py,pz)
|
||||
, normal (nx,ny,nz)
|
||||
, uv (uvx,uvy,0.0)
|
||||
{}
|
||||
:
|
||||
position(px, py, pz), normal(nx, ny, nz), uv(uvx, uvy, 0.0) {}
|
||||
|
||||
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
|
||||
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
||||
BatchLoader& batch,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiNodeAnim*>& anims,
|
||||
std::vector<AttachmentInfo>& attach,
|
||||
std::vector<aiMaterial*>& materials,
|
||||
unsigned int& defaultMatIdx);
|
||||
void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
|
||||
BatchLoader &batch,
|
||||
std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiNodeAnim *> &anims,
|
||||
std::vector<AttachmentInfo> &attach,
|
||||
std::vector<aiMaterial *> &materials,
|
||||
unsigned int &defaultMatIdx);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Generate a mesh that consists of just a single quad
|
||||
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
|
||||
const SkyboxVertex& v2,
|
||||
const SkyboxVertex& v3,
|
||||
const SkyboxVertex& v4);
|
||||
aiMesh *BuildSingleQuadMesh(const SkyboxVertex &v1,
|
||||
const SkyboxVertex &v2,
|
||||
const SkyboxVertex &v3,
|
||||
const SkyboxVertex &v4);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Build a sky-box
|
||||
|
@ -245,8 +248,8 @@ private:
|
|||
/// @param meshes Receives 6 output meshes
|
||||
/// @param materials The last 6 materials are assigned to the newly
|
||||
/// created meshes. The names of the materials are adjusted.
|
||||
void BuildSkybox(std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiMaterial*> materials);
|
||||
void BuildSkybox(std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiMaterial *> materials);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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 mesh Mesh to work on
|
||||
*/
|
||||
void CopyMaterial(std::vector<aiMaterial*>& materials,
|
||||
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
|
||||
unsigned int& defMatIdx,
|
||||
aiMesh* mesh);
|
||||
void CopyMaterial(std::vector<aiMaterial *> &materials,
|
||||
std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
|
||||
unsigned int &defMatIdx,
|
||||
aiMesh *mesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compute animations for a specific node
|
||||
|
@ -267,8 +270,8 @@ private:
|
|||
* @param root Node to be processed
|
||||
* @param anims The list of output animations
|
||||
*/
|
||||
void ComputeAnimations(Node* root, aiNode* real,
|
||||
std::vector<aiNodeAnim*>& anims);
|
||||
void ComputeAnimations(Node *root, aiNode *real,
|
||||
std::vector<aiNodeAnim *> &anims);
|
||||
|
||||
private:
|
||||
/// Configuration option: desired output FPS
|
||||
|
@ -276,6 +279,12 @@ private:
|
|||
|
||||
/// Configuration option: speed flag was set?
|
||||
bool configSpeedFlag;
|
||||
|
||||
std::vector<aiCamera*> cameras;
|
||||
std::vector<aiLight*> lights;
|
||||
unsigned int guessedMeshCnt;
|
||||
unsigned int guessedMatCnt;
|
||||
unsigned int guessedAnimCnt;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -57,25 +57,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Irrlicht Mesh Reader",
|
||||
"",
|
||||
"",
|
||||
"http://irrlicht.sourceforge.net/",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"xml irrmesh"
|
||||
"Irrlicht Mesh Reader",
|
||||
"",
|
||||
"",
|
||||
"http://irrlicht.sourceforge.net/",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"xml irrmesh"
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
IRRMeshImporter::IRRMeshImporter() :
|
||||
BaseImporter(),
|
||||
IrrlichtBase() {
|
||||
// empty
|
||||
}
|
||||
IRRMeshImporter::IRRMeshImporter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
|
@ -84,419 +80,443 @@ IRRMeshImporter::~IRRMeshImporter() = default;
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||
/* NOTE: A simple check for the file extension is not enough
|
||||
* here. Irrmesh and irr are easy, but xml is too generic
|
||||
* and could be collada, too. So we need to open the file and
|
||||
* search for typical tokens.
|
||||
*/
|
||||
static const char *tokens[] = { "irrmesh" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
||||
/* NOTE: A simple check for the file extension is not enough
|
||||
* here. Irrmesh and irr are easy, but xml is too generic
|
||||
* and could be collada, too. So we need to open the file and
|
||||
* search for typical tokens.
|
||||
*/
|
||||
static const char *tokens[] = { "irrmesh" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a list of all file extensions which are handled by this class
|
||||
const aiImporterDesc *IRRMeshImporter::GetInfo() const {
|
||||
return &desc;
|
||||
return &desc;
|
||||
}
|
||||
|
||||
static void releaseMaterial(aiMaterial **mat) {
|
||||
if (*mat != nullptr) {
|
||||
delete *mat;
|
||||
*mat = nullptr;
|
||||
}
|
||||
if (*mat != nullptr) {
|
||||
delete *mat;
|
||||
*mat = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void releaseMesh(aiMesh **mesh) {
|
||||
if (*mesh != nullptr) {
|
||||
delete *mesh;
|
||||
*mesh = nullptr;
|
||||
}
|
||||
if (*mesh != nullptr) {
|
||||
delete *mesh;
|
||||
*mesh = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(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 IRRMESH file ", pFile);
|
||||
// Check whether we can read from the file
|
||||
if (file == nullptr)
|
||||
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
|
||||
|
||||
// Construct the irrXML parser
|
||||
XmlParser parser;
|
||||
if (!parser.parse( file.get() )) {
|
||||
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
|
||||
}
|
||||
XmlNode root = parser.getRootNode();
|
||||
// Construct the irrXML parser
|
||||
XmlParser parser;
|
||||
if (!parser.parse(file.get())) {
|
||||
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
|
||||
}
|
||||
XmlNode root = parser.getRootNode();
|
||||
|
||||
// final data
|
||||
std::vector<aiMaterial *> materials;
|
||||
std::vector<aiMesh *> meshes;
|
||||
materials.reserve(5);
|
||||
meshes.reserve(5);
|
||||
// final data
|
||||
std::vector<aiMaterial *> materials;
|
||||
std::vector<aiMesh *> meshes;
|
||||
materials.reserve(5);
|
||||
meshes.reserve(5);
|
||||
|
||||
// temporary data - current mesh buffer
|
||||
aiMaterial *curMat = nullptr;
|
||||
aiMesh *curMesh = nullptr;
|
||||
unsigned int curMatFlags = 0;
|
||||
// temporary data - current mesh buffer
|
||||
// TODO move all these to inside loop
|
||||
aiMaterial *curMat = nullptr;
|
||||
aiMesh *curMesh = nullptr;
|
||||
unsigned int curMatFlags = 0;
|
||||
|
||||
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
|
||||
std::vector<aiColor4D> curColors;
|
||||
std::vector<aiVector3D> curUVs, curUV2s;
|
||||
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
|
||||
std::vector<aiColor4D> curColors;
|
||||
std::vector<aiVector3D> curUVs, curUV2s;
|
||||
|
||||
// some temporary variables
|
||||
int textMeaning = 0;
|
||||
int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
|
||||
bool useColors = false;
|
||||
// some temporary variables
|
||||
// textMeaning is a 15 year old variable, that could've been an enum
|
||||
// int textMeaning = 0; // 0=none? 1=vertices 2=indices
|
||||
// int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
|
||||
bool useColors = false;
|
||||
|
||||
// Parse the XML file
|
||||
for (pugi::xml_node child : root.children()) {
|
||||
if (child.type() == pugi::node_element) {
|
||||
if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) {
|
||||
// end of previous buffer. A material and a mesh should be there
|
||||
if (!curMat || !curMesh) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
||||
releaseMaterial(&curMat);
|
||||
releaseMesh(&curMesh);
|
||||
} else {
|
||||
materials.push_back(curMat);
|
||||
meshes.push_back(curMesh);
|
||||
}
|
||||
curMat = nullptr;
|
||||
curMesh = nullptr;
|
||||
/*
|
||||
** 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?
|
||||
*/
|
||||
|
||||
curVertices.clear();
|
||||
curColors.clear();
|
||||
curNormals.clear();
|
||||
curUV2s.clear();
|
||||
curUVs.clear();
|
||||
curTangents.clear();
|
||||
curBitangents.clear();
|
||||
}
|
||||
// Parse the XML file
|
||||
pugi::xml_node const &meshNode = root.child("mesh");
|
||||
for (pugi::xml_node bufferNode : meshNode.children()) {
|
||||
if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
|
||||
// Might be a useless warning
|
||||
ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ASSIMP_stricmp(child.name(), "material")) {
|
||||
if (curMat) {
|
||||
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
|
||||
releaseMaterial(&curMat);
|
||||
}
|
||||
curMat = ParseMaterial(curMatFlags);
|
||||
}
|
||||
/* 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");
|
||||
curMat = nullptr;
|
||||
curMesh = nullptr;
|
||||
|
||||
if (!num) {
|
||||
// This is possible ... remove the mesh from the list and skip further reading
|
||||
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
|
||||
curVertices.clear();
|
||||
curColors.clear();
|
||||
curNormals.clear();
|
||||
curUV2s.clear();
|
||||
curUVs.clear();
|
||||
curTangents.clear();
|
||||
curBitangents.clear();
|
||||
|
||||
releaseMaterial(&curMat);
|
||||
releaseMesh(&curMesh);
|
||||
textMeaning = 0;
|
||||
continue;
|
||||
}
|
||||
// TODO ensure all three nodes are present and populated
|
||||
// before allocating everything
|
||||
|
||||
curVertices.reserve(num);
|
||||
curNormals.reserve(num);
|
||||
curColors.reserve(num);
|
||||
curUVs.reserve(num);
|
||||
// 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");
|
||||
}
|
||||
} else {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Buffer must contain one material");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine the file format
|
||||
//const char *t = reader->getAttributeValueSafe("type");
|
||||
pugi::xml_attribute t = child.attribute("type");
|
||||
if (!ASSIMP_stricmp("2tcoords", t.name())) {
|
||||
curUV2s.reserve(num);
|
||||
vertexFormat = 1;
|
||||
// Get first vertices node
|
||||
pugi::xml_node verticesNode = bufferNode.child("vertices");
|
||||
if (verticesNode) {
|
||||
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
|
||||
};
|
||||
|
||||
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
|
||||
// *********************************************************
|
||||
// We have a second texture! So use this UV channel
|
||||
// for it. The 2nd texture can be either a normal
|
||||
// texture (solid_2layer or lightmap_xxx) or a normal
|
||||
// map (normal_..., parallax_...)
|
||||
// *********************************************************
|
||||
int idx = 1;
|
||||
aiMaterial *mat = (aiMaterial *)curMat;
|
||||
curVertices.reserve(vertexCount);
|
||||
curNormals.reserve(vertexCount);
|
||||
curColors.reserve(vertexCount);
|
||||
curUVs.reserve(vertexCount);
|
||||
|
||||
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
|
||||
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
|
||||
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
|
||||
}
|
||||
}
|
||||
} else if (!ASSIMP_stricmp("tangents", t.name())) {
|
||||
curTangents.reserve(num);
|
||||
curBitangents.reserve(num);
|
||||
vertexFormat = 2;
|
||||
} else if (ASSIMP_stricmp("standard", t.name())) {
|
||||
releaseMaterial(&curMat);
|
||||
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
|
||||
} else
|
||||
vertexFormat = 0;
|
||||
textMeaning = 1;
|
||||
} else if (!ASSIMP_stricmp(child.name(), "indices")) {
|
||||
if (curVertices.empty() && curMat) {
|
||||
releaseMaterial(&curMat);
|
||||
throw DeadlyImportError("IRRMESH: indices must come after vertices");
|
||||
}
|
||||
VertexFormat vertexFormat;
|
||||
// Determine the file format
|
||||
pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
|
||||
if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
|
||||
curUV2s.reserve(vertexCount);
|
||||
vertexFormat = VertexFormat::t2coord;
|
||||
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
|
||||
// *********************************************************
|
||||
// We have a second texture! So use this UV channel
|
||||
// for it. The 2nd texture can be either a normal
|
||||
// texture (solid_2layer or lightmap_xxx) or a normal
|
||||
// map (normal_..., parallax_...)
|
||||
// *********************************************************
|
||||
int idx = 1;
|
||||
aiMaterial *mat = (aiMaterial *)curMat;
|
||||
|
||||
textMeaning = 2;
|
||||
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
|
||||
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
|
||||
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
|
||||
}
|
||||
}
|
||||
} else if (!ASSIMP_stricmp("tangents", typeAttrib.value())) {
|
||||
curTangents.reserve(vertexCount);
|
||||
curBitangents.reserve(vertexCount);
|
||||
vertexFormat = VertexFormat::tangent;
|
||||
} 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);
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Unknown vertex format");
|
||||
continue; // Skip rest of buffer
|
||||
};
|
||||
|
||||
// start a new mesh
|
||||
curMesh = new aiMesh();
|
||||
// We know what format buffer is, collect numbers
|
||||
ParseBufferVertices(verticesNode.text().get(), vertexFormat,
|
||||
curVertices, curNormals,
|
||||
curTangents, curBitangents,
|
||||
curUVs, curUV2s, curColors, useColors);
|
||||
}
|
||||
|
||||
// allocate storage for all faces
|
||||
pugi::xml_attribute attr = child.attribute("indexCount");
|
||||
curMesh->mNumVertices = attr.as_int();
|
||||
if (!curMesh->mNumVertices) {
|
||||
// This is possible ... remove the mesh from the list and skip further reading
|
||||
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
|
||||
// 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
|
||||
curMesh = new aiMesh();
|
||||
|
||||
// mesh - away
|
||||
releaseMesh(&curMesh);
|
||||
// allocate storage for all faces
|
||||
pugi::xml_attribute attr = indicesNode.attribute("indexCount");
|
||||
curMesh->mNumVertices = attr.as_int();
|
||||
if (!curMesh->mNumVertices) {
|
||||
// This is possible ... remove the mesh from the list and skip further reading
|
||||
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
|
||||
|
||||
// material - away
|
||||
releaseMaterial(&curMat);
|
||||
// mesh - away
|
||||
releaseMesh(&curMesh);
|
||||
|
||||
textMeaning = 0;
|
||||
continue;
|
||||
}
|
||||
// material - away
|
||||
releaseMaterial(&curMat);
|
||||
continue; // Go to next buffer
|
||||
}
|
||||
|
||||
if (curMesh->mNumVertices % 3) {
|
||||
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
|
||||
}
|
||||
if (curMesh->mNumVertices % 3) {
|
||||
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
|
||||
}
|
||||
|
||||
curMesh->mNumFaces = curMesh->mNumVertices / 3;
|
||||
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
|
||||
curMesh->mNumFaces = curMesh->mNumVertices / 3;
|
||||
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
|
||||
|
||||
// setup some members
|
||||
curMesh->mMaterialIndex = (unsigned int)materials.size();
|
||||
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||
// setup some members
|
||||
curMesh->mMaterialIndex = (unsigned int)materials.size();
|
||||
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||
|
||||
// allocate storage for all vertices
|
||||
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
|
||||
// allocate storage for all vertices
|
||||
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
|
||||
|
||||
if (curNormals.size() == curVertices.size()) {
|
||||
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curTangents.size() == curVertices.size()) {
|
||||
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curBitangents.size() == curVertices.size()) {
|
||||
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curColors.size() == curVertices.size() && useColors) {
|
||||
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curUVs.size() == curVertices.size()) {
|
||||
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curUV2s.size() == curVertices.size()) {
|
||||
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
}
|
||||
//break;
|
||||
if (curNormals.size() == curVertices.size()) {
|
||||
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curTangents.size() == curVertices.size()) {
|
||||
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curBitangents.size() == curVertices.size()) {
|
||||
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curColors.size() == curVertices.size() && useColors) {
|
||||
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curUVs.size() == curVertices.size()) {
|
||||
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
if (curUV2s.size() == curVertices.size()) {
|
||||
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
|
||||
}
|
||||
|
||||
//case EXN_TEXT: {
|
||||
const char *sz = child.child_value();
|
||||
if (textMeaning == 1) {
|
||||
textMeaning = 0;
|
||||
// read indices
|
||||
aiFace *curFace = curMesh->mFaces;
|
||||
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
|
||||
|
||||
// read vertices
|
||||
do {
|
||||
SkipSpacesAndLineEnd(&sz);
|
||||
aiVector3D temp;
|
||||
aiColor4D c;
|
||||
aiVector3D *pcV = curMesh->mVertices;
|
||||
aiVector3D *pcN = curMesh->mNormals;
|
||||
aiVector3D *pcT = curMesh->mTangents;
|
||||
aiVector3D *pcB = curMesh->mBitangents;
|
||||
aiColor4D *pcC0 = curMesh->mColors[0];
|
||||
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
|
||||
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
|
||||
|
||||
// Read the vertex position
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
unsigned int curIdx = 0;
|
||||
unsigned int total = 0;
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
// 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)) {
|
||||
if (curFace >= faceEnd) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
||||
break;
|
||||
}
|
||||
// if new face
|
||||
if (!curIdx) {
|
||||
curFace->mNumIndices = 3;
|
||||
curFace->mIndices = new unsigned int[3];
|
||||
}
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
curVertices.push_back(temp);
|
||||
// Read index base 10
|
||||
// function advances the pointer
|
||||
unsigned int idx = strtoul10(sz, &sz);
|
||||
if (idx >= curVertices.size()) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
// Read the vertex normals
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
// make up our own indices?
|
||||
curFace->mIndices[curIdx] = total++;
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
// Copy over data to aiMesh
|
||||
*pcV++ = curVertices[idx];
|
||||
if (pcN) *pcN++ = curNormals[idx];
|
||||
if (pcT) *pcT++ = curTangents[idx];
|
||||
if (pcB) *pcB++ = curBitangents[idx];
|
||||
if (pcC0) *pcC0++ = curColors[idx];
|
||||
if (pcT0) *pcT0++ = curUVs[idx];
|
||||
if (pcT1) *pcT1++ = curUV2s[idx];
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
curNormals.push_back(temp);
|
||||
// start new face
|
||||
if (++curIdx == 3) {
|
||||
++curFace;
|
||||
curIdx = 0;
|
||||
}
|
||||
}
|
||||
// We should be at the end of mFaces
|
||||
if (curFace != faceEnd)
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
|
||||
}
|
||||
|
||||
// read the vertex colors
|
||||
uint32_t clr = strtoul16(sz, &sz);
|
||||
ColorFromARGBPacked(clr, c);
|
||||
// Finish processing the mesh - do some small material workarounds
|
||||
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
|
||||
// Take the opacity value of the current material
|
||||
// from the common vertex color alpha
|
||||
aiMaterial *mat = (aiMaterial *)curMat;
|
||||
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
|
||||
}
|
||||
// textMeaning = 2;
|
||||
|
||||
if (!curColors.empty() && c != *(curColors.end() - 1))
|
||||
useColors = true;
|
||||
// end of previous buffer. A material and a mesh should be there
|
||||
if (!curMat || !curMesh) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
||||
releaseMaterial(&curMat);
|
||||
releaseMesh(&curMesh);
|
||||
} else {
|
||||
materials.push_back(curMat);
|
||||
meshes.push_back(curMesh);
|
||||
}
|
||||
}
|
||||
|
||||
curColors.push_back(c);
|
||||
SkipSpaces(&sz);
|
||||
// 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");
|
||||
}
|
||||
|
||||
// read the first UV coordinate set
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
// now generate the output scene
|
||||
pScene->mNumMeshes = (unsigned int)meshes.size();
|
||||
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
pScene->mMeshes[i] = meshes[i];
|
||||
|
||||
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);
|
||||
// clean this value ...
|
||||
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
|
||||
}
|
||||
|
||||
// read the (optional) second UV coordinate set
|
||||
if (vertexFormat == 1) {
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
pScene->mNumMaterials = (unsigned int)materials.size();
|
||||
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
||||
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
|
||||
|
||||
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);
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mName.Set("<IRRMesh>");
|
||||
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
pScene->mRootNode->mMeshes[i] = i;
|
||||
};
|
||||
}
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
temp.y *= -1.0f;
|
||||
curTangents.push_back(temp);
|
||||
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;
|
||||
|
||||
// bitangents
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
// Read the vertex position
|
||||
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);
|
||||
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
temp.y *= -1.0f;
|
||||
curBitangents.push_back(temp);
|
||||
}
|
||||
}
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
vertices.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.
|
||||
*/
|
||||
// Read the vertex normals
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
while (SkipLine(&sz));
|
||||
} else if (textMeaning == 2) {
|
||||
textMeaning = 0;
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
// read indices
|
||||
aiFace *curFace = curMesh->mFaces;
|
||||
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
normals.push_back(temp);
|
||||
|
||||
aiVector3D *pcV = curMesh->mVertices;
|
||||
aiVector3D *pcN = curMesh->mNormals;
|
||||
aiVector3D *pcT = curMesh->mTangents;
|
||||
aiVector3D *pcB = curMesh->mBitangents;
|
||||
aiColor4D *pcC0 = curMesh->mColors[0];
|
||||
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
|
||||
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
|
||||
// read the vertex colors
|
||||
uint32_t clr = strtoul16(sz, &sz);
|
||||
ColorFromARGBPacked(clr, c);
|
||||
|
||||
unsigned int curIdx = 0;
|
||||
unsigned int total = 0;
|
||||
while (SkipSpacesAndLineEnd(&sz)) {
|
||||
if (curFace >= faceEnd) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
||||
break;
|
||||
}
|
||||
if (!curIdx) {
|
||||
curFace->mNumIndices = 3;
|
||||
curFace->mIndices = new unsigned int[3];
|
||||
}
|
||||
// If we're pushing more than one distinct color
|
||||
if (!colors.empty() && c != *(colors.end() - 1))
|
||||
useColors = true;
|
||||
|
||||
unsigned int idx = strtoul10(sz, &sz);
|
||||
if (idx >= curVertices.size()) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
|
||||
idx = 0;
|
||||
}
|
||||
colors.push_back(c);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
curFace->mIndices[curIdx] = total++;
|
||||
// read the first UV coordinate set
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
*pcV++ = curVertices[idx];
|
||||
if (pcN) *pcN++ = curNormals[idx];
|
||||
if (pcT) *pcT++ = curTangents[idx];
|
||||
if (pcB) *pcB++ = curBitangents[idx];
|
||||
if (pcC0) *pcC0++ = curColors[idx];
|
||||
if (pcT0) *pcT0++ = curUVs[idx];
|
||||
if (pcT1) *pcT1++ = curUV2s[idx];
|
||||
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);
|
||||
|
||||
if (++curIdx == 3) {
|
||||
++curFace;
|
||||
curIdx = 0;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
if (curFace != faceEnd)
|
||||
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
|
||||
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);
|
||||
|
||||
// Finish processing the mesh - do some small material workarounds
|
||||
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
|
||||
// Take the opacity value of the current material
|
||||
// from the common vertex color alpha
|
||||
aiMaterial *mat = (aiMaterial *)curMat;
|
||||
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
// End of the last buffer. A material and a mesh should be there
|
||||
if (curMat || curMesh) {
|
||||
if (!curMat || !curMesh) {
|
||||
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
||||
releaseMaterial(&curMat);
|
||||
releaseMesh(&curMesh);
|
||||
} else {
|
||||
materials.push_back(curMat);
|
||||
meshes.push_back(curMesh);
|
||||
}
|
||||
}
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
temp.y *= -1.0f;
|
||||
tangents.push_back(temp);
|
||||
|
||||
if (materials.empty()) {
|
||||
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
|
||||
}
|
||||
// bitangents
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
// now generate the output scene
|
||||
pScene->mNumMeshes = (unsigned int)meshes.size();
|
||||
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
pScene->mMeshes[i] = meshes[i];
|
||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
// clean this value ...
|
||||
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
|
||||
}
|
||||
|
||||
pScene->mNumMaterials = (unsigned int)materials.size();
|
||||
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
||||
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
|
||||
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mName.Set("<IRRMesh>");
|
||||
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
||||
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
pScene->mRootNode->mMeshes[i] = i;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -85,6 +85,19 @@ protected:
|
|||
*/
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||
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
|
||||
|
|
|
@ -43,302 +43,302 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @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))
|
||||
|
||||
#include "IRRShared.h"
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// Transformation matrix to convert from Assimp to IRR space
|
||||
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a property in hexadecimal format (i.e. ffffffff)
|
||||
void IrrlichtBase::ReadHexProperty(HexProperty &out ) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
|
||||
for (pugi::xml_attribute attrib : hexnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string( attrib.value() );
|
||||
} else if (!ASSIMP_stricmp(attrib.name(),"value")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// parse the hexadecimal value
|
||||
out.value = strtoul16(attrib.name());
|
||||
out.value = strtoul16(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a decimal property
|
||||
void IrrlichtBase::ReadIntProperty(IntProperty & out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.value(),"value")) {
|
||||
void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
|
||||
for (pugi::xml_attribute attrib : intnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// parse the int value
|
||||
out.value = strtol10(attrib.name());
|
||||
out.value = strtol10(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a string property
|
||||
void IrrlichtBase::ReadStringProperty( StringProperty& out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
|
||||
for (pugi::xml_attribute attrib : stringnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// simple copy the string
|
||||
out.value = std::string(attrib.value());
|
||||
out.value = std::string(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a boolean property
|
||||
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")){
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
|
||||
for (pugi::xml_attribute attrib : boolnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// true or false, case insensitive
|
||||
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
|
||||
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a float property
|
||||
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
|
||||
for (pugi::xml_attribute attrib : floatnode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// just parse the float
|
||||
out.value = fast_atof(attrib.value());
|
||||
out.value = fast_atof(attrib.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a vector property
|
||||
void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
|
||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
|
||||
for (pugi::xml_attribute attrib : vectornode.attributes()) {
|
||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||
out.name = std::string(attrib.value());
|
||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||
// three floats, separated with commas
|
||||
const char *ptr = attrib.value();
|
||||
|
||||
SkipSpaces(&ptr);
|
||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
|
||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
|
||||
SkipSpaces(&ptr);
|
||||
if (',' != *ptr) {
|
||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||
} else {
|
||||
SkipSpaces(ptr + 1, &ptr);
|
||||
}
|
||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
|
||||
} else {
|
||||
SkipSpaces(ptr + 1, &ptr);
|
||||
}
|
||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
|
||||
SkipSpaces(&ptr);
|
||||
if (',' != *ptr) {
|
||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||
} else {
|
||||
SkipSpaces(ptr + 1, &ptr);
|
||||
}
|
||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
|
||||
} else {
|
||||
SkipSpaces(ptr + 1, &ptr);
|
||||
}
|
||||
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a string to a proper aiMappingMode
|
||||
int ConvertMappingMode(const std::string& mode) {
|
||||
int ConvertMappingMode(const std::string &mode) {
|
||||
if (mode == "texture_clamp_repeat") {
|
||||
return aiTextureMapMode_Wrap;
|
||||
} else if (mode == "texture_clamp_mirror") {
|
||||
return aiTextureMapMode_Mirror;
|
||||
}
|
||||
} else if (mode == "texture_clamp_mirror") {
|
||||
return aiTextureMapMode_Mirror;
|
||||
}
|
||||
|
||||
return aiTextureMapMode_Clamp;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Parse a material from the XML file
|
||||
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
|
||||
aiMaterial* mat = new aiMaterial();
|
||||
aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
|
||||
aiMaterial *mat = new aiMaterial();
|
||||
aiColor4D clr;
|
||||
aiString s;
|
||||
|
||||
matFlags = 0; // zero output flags
|
||||
int cnt = 0; // number of used texture channels
|
||||
int cnt = 0; // number of used texture channels
|
||||
unsigned int nd = 0;
|
||||
|
||||
for (pugi::xml_node child : mNode->children()) {
|
||||
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
|
||||
HexProperty prop;
|
||||
ReadHexProperty(prop);
|
||||
if (prop.name == "Diffuse") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
} else if (prop.name == "Ambient") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
} else if (prop.name == "Specular") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
}
|
||||
for (pugi::xml_node child : materialNode.children()) {
|
||||
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
|
||||
HexProperty prop;
|
||||
ReadHexProperty(prop, child);
|
||||
if (prop.name == "Diffuse") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
} else if (prop.name == "Ambient") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
} else if (prop.name == "Specular") {
|
||||
ColorFromARGBPacked(prop.value, clr);
|
||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
}
|
||||
|
||||
// NOTE: The 'emissive' property causes problems. It is
|
||||
// often != 0, even if there is obviously no light
|
||||
// emitted by the described surface. In fact I think
|
||||
// IRRLICHT ignores this property, too.
|
||||
// NOTE: The 'emissive' property causes problems. It is
|
||||
// often != 0, even if there is obviously no light
|
||||
// emitted by the described surface. In fact I think
|
||||
// IRRLICHT ignores this property, too.
|
||||
#if 0
|
||||
else if (prop.name == "Emissive") {
|
||||
ColorFromARGBPacked(prop.value,clr);
|
||||
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
|
||||
}
|
||||
#endif
|
||||
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop);
|
||||
if (prop.name == "Shininess") {
|
||||
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
|
||||
BoolProperty prop;
|
||||
ReadBoolProperty(prop);
|
||||
if (prop.name == "Wireframe") {
|
||||
int val = (prop.value ? true : false);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
} else if (prop.name == "GouraudShading") {
|
||||
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
|
||||
} else if (prop.name == "BackfaceCulling") {
|
||||
int val = (!prop.value);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
|
||||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
|
||||
StringProperty prop;
|
||||
ReadStringProperty(prop);
|
||||
if (prop.value.length()) {
|
||||
// material type (shader)
|
||||
if (prop.name == "Type") {
|
||||
if (prop.value == "solid") {
|
||||
// default material ...
|
||||
} else if (prop.value == "trans_vertex_alpha") {
|
||||
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
|
||||
} else if (prop.value == "lightmap") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap;
|
||||
} else if (prop.value == "solid_2layer") {
|
||||
matFlags = AI_IRRMESH_MAT_solid_2layer;
|
||||
} else if (prop.value == "lightmap_m2") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_m2;
|
||||
} else if (prop.value == "lightmap_m4") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_m4;
|
||||
} else if (prop.value == "lightmap_light") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light;
|
||||
} else if (prop.value == "lightmap_light_m2") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
|
||||
} else if (prop.value == "lightmap_light_m4") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
|
||||
} else if (prop.value == "lightmap_add") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_add;
|
||||
} else if (prop.value == "normalmap_solid" ||
|
||||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_solid;
|
||||
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
|
||||
prop.value == "parallaxmap_trans_vertex_alpha") {
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_tva;
|
||||
} else if (prop.value == "normalmap_trans_add" ||
|
||||
prop.value == "parallaxmap_trans_add") {
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_ta;
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
|
||||
}
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
|
||||
FloatProperty prop;
|
||||
ReadFloatProperty(prop, child);
|
||||
if (prop.name == "Shininess") {
|
||||
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
|
||||
BoolProperty prop;
|
||||
ReadBoolProperty(prop, child);
|
||||
if (prop.name == "Wireframe") {
|
||||
int val = (prop.value ? true : false);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
} else if (prop.name == "GouraudShading") {
|
||||
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
|
||||
} else if (prop.name == "BackfaceCulling") {
|
||||
int val = (!prop.value);
|
||||
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
|
||||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
|
||||
StringProperty prop;
|
||||
ReadStringProperty(prop, child);
|
||||
if (prop.value.length()) {
|
||||
// material type (shader)
|
||||
if (prop.name == "Type") {
|
||||
if (prop.value == "solid") {
|
||||
// default material ...
|
||||
} else if (prop.value == "trans_vertex_alpha") {
|
||||
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
|
||||
} else if (prop.value == "lightmap") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap;
|
||||
} else if (prop.value == "solid_2layer") {
|
||||
matFlags = AI_IRRMESH_MAT_solid_2layer;
|
||||
} else if (prop.value == "lightmap_m2") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_m2;
|
||||
} else if (prop.value == "lightmap_m4") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_m4;
|
||||
} else if (prop.value == "lightmap_light") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light;
|
||||
} else if (prop.value == "lightmap_light_m2") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
|
||||
} else if (prop.value == "lightmap_light_m4") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
|
||||
} else if (prop.value == "lightmap_add") {
|
||||
matFlags = AI_IRRMESH_MAT_lightmap_add;
|
||||
} else if (prop.value == "normalmap_solid" ||
|
||||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_solid;
|
||||
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
|
||||
prop.value == "parallaxmap_trans_vertex_alpha") {
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_tva;
|
||||
} else if (prop.value == "normalmap_trans_add" ||
|
||||
prop.value == "parallaxmap_trans_add") {
|
||||
matFlags = AI_IRRMESH_MAT_normalmap_ta;
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Up to 4 texture channels are supported
|
||||
if (prop.name == "Texture1") {
|
||||
// Always accept the primary texture channel
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
} else if (prop.name == "Texture2" && cnt == 1) {
|
||||
// 2-layer material lightmapped?
|
||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
|
||||
// Up to 4 texture channels are supported
|
||||
if (prop.name == "Texture1") {
|
||||
// Always accept the primary texture channel
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
} else if (prop.name == "Texture2" && cnt == 1) {
|
||||
// 2-layer material lightmapped?
|
||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
|
||||
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
|
||||
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
|
||||
++nd;
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
|
||||
++nd;
|
||||
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
|
||||
}
|
||||
} else if (prop.name == "Texture3" && cnt == 2) {
|
||||
// Irrlicht does not seem to use these channels.
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
|
||||
} else if (prop.name == "Texture4" && cnt == 3) {
|
||||
// Irrlicht does not seem to use these channels.
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
|
||||
}
|
||||
// set the corresponding material flag
|
||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||
} else {
|
||||
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
|
||||
}
|
||||
} else if (prop.name == "Texture3" && cnt == 2) {
|
||||
// Irrlicht does not seem to use these channels.
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
|
||||
} else if (prop.name == "Texture4" && cnt == 3) {
|
||||
// Irrlicht does not seem to use these channels.
|
||||
++cnt;
|
||||
s.Set(prop.value);
|
||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
|
||||
}
|
||||
|
||||
// Texture mapping options
|
||||
if (prop.name == "TextureWrap1" && cnt >= 1) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
|
||||
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
|
||||
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
|
||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
|
||||
}
|
||||
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
|
||||
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
//break;
|
||||
/*case EXN_ELEMENT_END:
|
||||
// Texture mapping options
|
||||
if (prop.name == "TextureWrap1" && cnt >= 1) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
|
||||
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
|
||||
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
|
||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
|
||||
}
|
||||
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
|
||||
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
|
||||
int map = ConvertMappingMode(prop.value);
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
|
||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
// break;
|
||||
/*case EXN_ELEMENT_END:
|
||||
|
||||
// Assume there are no further nested nodes in <material> elements
|
||||
if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
|
||||
|
@ -378,8 +378,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
|
|||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
|
||||
/** @file IRRShared.h
|
||||
* @brief Shared utilities for the IRR and IRRMESH loaders
|
||||
*/
|
||||
* @brief Shared utilities for the IRR and IRRMESH loaders
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_AI_IRRSHARED_H
|
||||
#define INCLUDED_AI_IRRSHARED_H
|
||||
|
@ -58,14 +58,11 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
|
|||
*/
|
||||
class IrrlichtBase {
|
||||
protected:
|
||||
IrrlichtBase() :
|
||||
mNode(nullptr) {
|
||||
IrrlichtBase() {
|
||||
// empty
|
||||
}
|
||||
|
||||
~IrrlichtBase() {
|
||||
// empty
|
||||
}
|
||||
~IrrlichtBase() = default;
|
||||
|
||||
/** @brief Data structure for a simple name-value property
|
||||
*/
|
||||
|
@ -84,25 +81,25 @@ protected:
|
|||
|
||||
/// XML reader instance
|
||||
XmlParser mParser;
|
||||
pugi::xml_node *mNode;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a material description from the XML
|
||||
* @return The created material
|
||||
* @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.
|
||||
* @param out Receives output data
|
||||
* @param node XML attribute element containing data
|
||||
*/
|
||||
void ReadHexProperty(HexProperty &out);
|
||||
void ReadStringProperty(StringProperty &out);
|
||||
void ReadBoolProperty(BoolProperty &out);
|
||||
void ReadFloatProperty(FloatProperty &out);
|
||||
void ReadVectorProperty(VectorProperty &out);
|
||||
void ReadIntProperty(IntProperty &out);
|
||||
void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
|
||||
void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
|
||||
void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
|
||||
void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
|
||||
void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
|
||||
void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -162,8 +162,11 @@ void AnimResolver::UpdateAnimRangeSetup() {
|
|||
const double my_last = (*it).keys.back().time;
|
||||
|
||||
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;
|
||||
|
||||
// NOTE: We won't handle reset, linear and constant here.
|
||||
|
@ -176,8 +179,7 @@ void AnimResolver::UpdateAnimRangeSetup() {
|
|||
case LWO::PrePostBehaviour_Oscillate: {
|
||||
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(),
|
||||
[start_time](double t) { return start_time > t; }),
|
||||
m;
|
||||
[start_time](double t) { return start_time > t; }), m;
|
||||
|
||||
size_t ofs = 0;
|
||||
if (n != (*it).keys.end()) {
|
||||
|
|
|
@ -65,7 +65,6 @@ void LWOImporter::LoadLWOBFile()
|
|||
if (mFileBuffer + head.length > end)
|
||||
{
|
||||
throw DeadlyImportError("LWOB: Invalid chunk length");
|
||||
break;
|
||||
}
|
||||
uint8_t* const next = mFileBuffer+head.length;
|
||||
switch (head.type)
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -51,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "AssetLib/LWO/LWOLoader.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
#include "Geometry/GeometryUtils.h"
|
||||
|
||||
#include <assimp/ByteSwapper.h>
|
||||
#include <assimp/SGSpatialSort.h>
|
||||
|
@ -178,7 +177,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
mLayers->push_back(Layer());
|
||||
mCurLayer = &mLayers->back();
|
||||
mCurLayer->mName = "<LWODefault>";
|
||||
mCurLayer->mIndex = (uint16_t) -1;
|
||||
mCurLayer->mIndex = 1;
|
||||
|
||||
// old lightwave file format (prior to v6)
|
||||
mIsLWO2 = false;
|
||||
|
@ -215,7 +214,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
} else {
|
||||
mIsLWO2 = true;
|
||||
}
|
||||
|
||||
|
||||
LoadLWO2File();
|
||||
|
||||
// The newer lightwave format allows the user to configure the
|
||||
|
@ -398,14 +397,6 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
pvVC[w]++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// process vertex weights. We can't properly reconstruct the whole skeleton for now,
|
||||
// but we can create dummy bones for all weight channels which we have.
|
||||
for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
face.mIndices[q] = vert;
|
||||
}
|
||||
pf->mIndices = face.mIndices;
|
||||
|
@ -429,7 +420,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
// Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
|
||||
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
|
||||
if (layer.mName != "<LWODefault>" || num > 0) {
|
||||
aiNode *pcNode = new aiNode();
|
||||
std::unique_ptr<aiNode> pcNode(new aiNode());
|
||||
pcNode->mName.Set(layer.mName);
|
||||
pcNode->mParent = (aiNode *)&layer;
|
||||
pcNode->mNumMeshes = num;
|
||||
|
@ -439,7 +430,8 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||
for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p)
|
||||
pcNode->mMeshes[p] = p + meshStart;
|
||||
}
|
||||
apcNodes[layer.mIndex] = pcNode;
|
||||
ASSIMP_LOG_DEBUG("insert apcNode for layer ", layer.mIndex, " \"", layer.mName, "\"");
|
||||
apcNodes[layer.mIndex] = pcNode.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,7 +527,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
continue;
|
||||
vNormals += v;
|
||||
}
|
||||
mesh->mNormals[idx] = vNormals.Normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +547,6 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
const aiVector3D &v = faceNormals[*a];
|
||||
vNormals += v;
|
||||
}
|
||||
vNormals.Normalize();
|
||||
for (std::vector<unsigned int>::const_iterator a = poResult.begin(); a != poResult.end(); ++a) {
|
||||
mesh->mNormals[*a] = vNormals;
|
||||
vertexDone[*a] = true;
|
||||
|
@ -564,6 +554,7 @@ void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector<unsigned int> &
|
|||
}
|
||||
}
|
||||
}
|
||||
GeometryUtils::normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -572,40 +563,64 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
|
|||
aiNode *root = mScene->mRootNode = new aiNode();
|
||||
root->mName.Set("<LWORoot>");
|
||||
|
||||
//Set parent of all children, inserting pivots
|
||||
std::map<uint16_t, aiNode *> mapPivot;
|
||||
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||
|
||||
//Get the parent index
|
||||
LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent);
|
||||
uint16_t parentIndex = nodeLayer->mParent;
|
||||
|
||||
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
||||
aiNode *pivotNode = new aiNode();
|
||||
pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
|
||||
itapcNodes->second->mParent = pivotNode;
|
||||
|
||||
//Look for the parent node to attach the pivot to
|
||||
if (apcNodes.find(parentIndex) != apcNodes.end()) {
|
||||
pivotNode->mParent = apcNodes[parentIndex];
|
||||
} else {
|
||||
//If not, attach to the root node
|
||||
pivotNode->mParent = root;
|
||||
}
|
||||
|
||||
//Set the node and the pivot node transformation
|
||||
itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
|
||||
itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
|
||||
itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
|
||||
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
||||
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
||||
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
||||
mapPivot[-(itapcNodes->first + 2)] = pivotNode;
|
||||
ASSIMP_LOG_DEBUG("apcNodes initial size: ", apcNodes.size());
|
||||
if (!apcNodes.empty()) {
|
||||
ASSIMP_LOG_DEBUG("first apcNode is: ", apcNodes.begin()->first, " \"", apcNodes.begin()->second->mName.C_Str(), "\"");
|
||||
}
|
||||
|
||||
//Merge pivot map into node map
|
||||
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
||||
apcNodes[itMapPivot->first] = itMapPivot->second;
|
||||
//Set parent of all children, inserting pivots
|
||||
{
|
||||
std::map<uint16_t, aiNode *> mapPivot;
|
||||
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||
|
||||
//Get the parent index
|
||||
LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent);
|
||||
uint16_t parentIndex = nodeLayer->mParent;
|
||||
|
||||
//Create pivot node, store it into the pivot map, and set the parent as the pivot
|
||||
std::unique_ptr<aiNode> pivotNode(new aiNode());
|
||||
pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data));
|
||||
itapcNodes->second->mParent = pivotNode.get();
|
||||
|
||||
//Look for the parent node to attach the pivot to
|
||||
if (apcNodes.find(parentIndex) != apcNodes.end()) {
|
||||
pivotNode->mParent = apcNodes[parentIndex];
|
||||
} else {
|
||||
//If not, attach to the root node
|
||||
pivotNode->mParent = root;
|
||||
}
|
||||
|
||||
//Set the node and the pivot node transformation
|
||||
itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
|
||||
itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
|
||||
itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
|
||||
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
||||
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
||||
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
||||
uint16_t pivotNodeId = static_cast<uint16_t>(-(itapcNodes->first + 2));
|
||||
ASSIMP_LOG_DEBUG("insert pivot node: ", pivotNodeId);
|
||||
auto oldNodeIt = mapPivot.find(pivotNodeId);
|
||||
if (oldNodeIt != mapPivot.end()) {
|
||||
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in pivot map ", pivotNodeId, " \"", pivotNode->mName.C_Str(), "\"");
|
||||
} else {
|
||||
mapPivot.emplace(pivotNodeId, pivotNode.release());
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG("pivot nodes: ", mapPivot.size());
|
||||
//Merge pivot map into node map
|
||||
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end();) {
|
||||
uint16_t pivotNodeId = itMapPivot->first;
|
||||
auto oldApcNodeIt = apcNodes.find(pivotNodeId);
|
||||
if (oldApcNodeIt != apcNodes.end()) {
|
||||
ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in apc nodes ", pivotNodeId, " \"", itMapPivot->second->mName.C_Str(), "\"");
|
||||
} else {
|
||||
apcNodes.emplace(pivotNodeId, itMapPivot->second);
|
||||
}
|
||||
itMapPivot->second = nullptr;
|
||||
itMapPivot = mapPivot.erase(itMapPivot);
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("total nodes: ", apcNodes.size());
|
||||
}
|
||||
|
||||
//Set children of all parents
|
||||
|
@ -627,8 +642,15 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t, aiNode *> &apcNodes) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!mScene->mRootNode->mNumChildren)
|
||||
if (!mScene->mRootNode->mNumChildren) {
|
||||
ASSIMP_LOG_DEBUG("All apcNodes:");
|
||||
for (auto nodeIt = apcNodes.begin(); nodeIt != apcNodes.end(); ) {
|
||||
ASSIMP_LOG_DEBUG("Node ", nodeIt->first, " \"", nodeIt->second->mName.C_Str(), "\"");
|
||||
nodeIt->second = nullptr;
|
||||
nodeIt = apcNodes.erase(nodeIt);
|
||||
}
|
||||
throw DeadlyImportError("LWO: Unable to build a valid node graph");
|
||||
}
|
||||
|
||||
// Remove a single root node with no meshes assigned to it ...
|
||||
if (1 == mScene->mRootNode->mNumChildren) {
|
||||
|
@ -1462,7 +1484,6 @@ void LWOImporter::LoadLWO2File() {
|
|||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO2: Chunk length points behind the file");
|
||||
break;
|
||||
}
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
|
|
|
@ -345,7 +345,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
|
|||
|
||||
// (the diffuse value is just a scaling factor)
|
||||
// If a diffuse texture is set, we set this value to 1.0
|
||||
clr = (b && false ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
|
||||
clr = (b ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor);
|
||||
clr.r *= surf.mDiffuseValue;
|
||||
clr.g *= surf.mDiffuseValue;
|
||||
clr.b *= surf.mDiffuseValue;
|
||||
|
|
|
@ -632,18 +632,17 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
nodes.push_back(d);
|
||||
}
|
||||
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'");
|
||||
} else {
|
||||
// important: index of channel
|
||||
nodes.back().channels.emplace_back();
|
||||
LWO::Envelope &env = nodes.back().channels.back();
|
||||
|
||||
env.index = strtoul10(c);
|
||||
|
||||
// currently we can just interpret the standard channels 0...9
|
||||
// (hack) assume that index-i yields the binary channel type from LWO
|
||||
env.type = (LWO::EnvelopeType)(env.index + 1);
|
||||
}
|
||||
|
||||
// important: index of channel
|
||||
nodes.back().channels.emplace_back();
|
||||
LWO::Envelope &env = nodes.back().channels.back();
|
||||
|
||||
env.index = strtoul10(c);
|
||||
|
||||
// currently we can just interpret the standard channels 0...9
|
||||
// (hack) assume that index-i yields the binary channel type from LWO
|
||||
env.type = (LWO::EnvelopeType)(env.index + 1);
|
||||
|
||||
}
|
||||
// 'Envelope': a single animation channel
|
||||
else if ((*it).tokens[0] == "Envelope") {
|
||||
|
|
|
@ -65,7 +65,7 @@ class M3DImporter : public BaseImporter {
|
|||
public:
|
||||
/// \brief Default constructor
|
||||
M3DImporter();
|
||||
~M3DImporter() override {}
|
||||
~M3DImporter() override = default;
|
||||
|
||||
/// \brief Returns whether the class can handle the format of the given file.
|
||||
/// \remark See BaseImporter::CanRead() for details.
|
||||
|
|
|
@ -39,8 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
|
||||
#if !defined ASSIMP_BUILD_NO_M3D_IMPORTER || !(defined ASSIMP_BUILD_NO_EXPORT || defined ASSIMP_BUILD_NO_M3D_EXPORTER)
|
||||
|
||||
#include "M3DWrapper.h"
|
||||
|
||||
|
@ -149,4 +148,3 @@ void M3DWrapper::ClearSave() {
|
|||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -47,8 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AI_M3DWRAPPER_H_INC
|
||||
#define AI_M3DWRAPPER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
|
||||
#if !defined ASSIMP_BUILD_NO_M3D_IMPORTER || !(defined ASSIMP_BUILD_NO_EXPORT || defined ASSIMP_BUILD_NO_M3D_EXPORTER)
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -126,7 +125,6 @@ inline m3d_t *M3DWrapper::M3D() const {
|
|||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
#endif // ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
|
||||
#endif // AI_M3DWRAPPER_H_INC
|
||||
|
|
|
@ -138,18 +138,31 @@ bool MD5Parser::ParseSection(Section &out) {
|
|||
char *sz = buffer;
|
||||
while (!IsSpaceOrNewLine(*buffer)) {
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
out.mName = std::string(sz, (uintptr_t)(buffer - sz));
|
||||
SkipSpaces();
|
||||
while (IsSpace(*buffer)) {
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
while (running) {
|
||||
if ('{' == *buffer) {
|
||||
// it is a normal section so read all lines
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
bool run = true;
|
||||
while (run) {
|
||||
if (!SkipSpacesAndLineEnd()) {
|
||||
while (IsSpaceOrNewLine(*buffer)) {
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
if ('\0' == *buffer) {
|
||||
return false; // seems this was the last section
|
||||
}
|
||||
if ('}' == *buffer) {
|
||||
|
@ -164,25 +177,39 @@ bool MD5Parser::ParseSection(Section &out) {
|
|||
elem.szStart = buffer;
|
||||
|
||||
// terminate the line with zero
|
||||
while (!IsLineEnd(*buffer))
|
||||
while (!IsLineEnd(*buffer)) {
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
if (*buffer) {
|
||||
++lineNumber;
|
||||
*buffer++ = '\0';
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (!IsSpaceOrNewLine(*buffer)) {
|
||||
// it is an element at global scope. Parse its value and go on
|
||||
sz = buffer;
|
||||
while (!IsSpaceOrNewLine(*buffer++))
|
||||
;
|
||||
while (!IsSpaceOrNewLine(*buffer++)) {
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SkipSpacesAndLineEnd();
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
while (IsSpaceOrNewLine(*buffer)) {
|
||||
++buffer;
|
||||
if (buffer == bufferEnd)
|
||||
return false;
|
||||
}
|
||||
return '\0' != *buffer;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -228,15 +255,20 @@ bool MD5Parser::ParseSection(Section &out) {
|
|||
out.data[out.length] = '\0';
|
||||
|
||||
// parse a string, enclosed in quotation marks
|
||||
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
|
||||
while ('\"' != *sz) \
|
||||
++sz; \
|
||||
const char *szStart = ++sz; \
|
||||
while ('\"' != *sz) \
|
||||
++sz; \
|
||||
const char *szEnd = (sz++); \
|
||||
out.length = (ai_uint32)(szEnd - szStart); \
|
||||
::memcpy(out.data, szStart, out.length); \
|
||||
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
|
||||
out.length = 0; \
|
||||
while ('\"' != *sz && '\0' != *sz) \
|
||||
++sz; \
|
||||
if ('\0' != *sz) { \
|
||||
const char *szStart = ++sz; \
|
||||
while ('\"' != *sz && '\0' != *sz) \
|
||||
++sz; \
|
||||
if ('\0' != *sz) { \
|
||||
const char *szEnd = (sz++); \
|
||||
out.length = (ai_uint32)(szEnd - szStart); \
|
||||
::memcpy(out.data, szStart, out.length); \
|
||||
} \
|
||||
} \
|
||||
out.data[out.length] = '\0';
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// .MD5MESH parsing function
|
||||
|
|
|
@ -365,9 +365,7 @@ public:
|
|||
static void ReportWarning (const char* warn, unsigned int line);
|
||||
|
||||
|
||||
void ReportError (const char* error) {
|
||||
return ReportError(error, lineNumber);
|
||||
}
|
||||
AI_WONT_RETURN void ReportError (const char* error) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
void ReportWarning (const char* warn) {
|
||||
return ReportWarning(warn, lineNumber);
|
||||
|
@ -394,7 +392,7 @@ private:
|
|||
|
||||
bool SkipLine(const char* in, const char** out);
|
||||
bool SkipLine( );
|
||||
bool SkipSpacesAndLineEnd( const char* in, const char** out);
|
||||
bool SkipSpacesAndLineEnd( const char* in, const char** out);
|
||||
bool SkipSpacesAndLineEnd();
|
||||
bool SkipSpaces();
|
||||
|
||||
|
@ -404,6 +402,9 @@ private:
|
|||
unsigned int lineNumber;
|
||||
};
|
||||
|
||||
inline void MD5Parser::ReportError(const char* error) {
|
||||
ReportError(error, lineNumber);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool MD5Parser::SkipLine(const char* in, const char** out) {
|
||||
++lineNumber;
|
||||
|
|
|
@ -470,14 +470,16 @@ void HL1MDLLoader::read_bones() {
|
|||
|
||||
temp_bones_.resize(header_->numbones);
|
||||
|
||||
// Create the main 'bones' node that will contain all MDL root bones.
|
||||
aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES);
|
||||
rootnode_children_.push_back(bones_node);
|
||||
bones_node->mNumChildren = static_cast<unsigned int>(header_->numbones);
|
||||
bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
|
||||
|
||||
// Store roots bones IDs temporarily.
|
||||
std::vector<int> roots;
|
||||
|
||||
// Create bone matrices in local space.
|
||||
for (int i = 0; i < header_->numbones; ++i) {
|
||||
aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]);
|
||||
aiNode *bone_node = temp_bones_[i].node = new aiNode(unique_bones_names[i]);
|
||||
|
||||
aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]);
|
||||
temp_bones_[i].absolute_transform = bone_node->mTransformation =
|
||||
|
@ -485,9 +487,11 @@ void HL1MDLLoader::read_bones() {
|
|||
aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2]));
|
||||
|
||||
if (pbone[i].parent == -1) {
|
||||
bone_node->mParent = scene_->mRootNode;
|
||||
bone_node->mParent = bones_node;
|
||||
roots.push_back(i); // This bone has no parent. Add it to the roots list.
|
||||
} else {
|
||||
bone_node->mParent = bones_node->mChildren[pbone[i].parent];
|
||||
bone_node->mParent = temp_bones_[pbone[i].parent].node;
|
||||
temp_bones_[pbone[i].parent].children.push_back(i); // Add this bone to the parent bone's children list.
|
||||
|
||||
temp_bones_[i].absolute_transform =
|
||||
temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation;
|
||||
|
@ -496,6 +500,36 @@ void HL1MDLLoader::read_bones() {
|
|||
temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform;
|
||||
temp_bones_[i].offset_matrix.Inverse();
|
||||
}
|
||||
|
||||
// Allocate memory for each MDL root bone.
|
||||
bones_node->mNumChildren = static_cast<unsigned int>(roots.size());
|
||||
bones_node->mChildren = new aiNode *[bones_node->mNumChildren];
|
||||
|
||||
// Build all bones children hierarchy starting from each MDL root bone.
|
||||
for (size_t i = 0; i < roots.size(); ++i)
|
||||
{
|
||||
const TempBone &root_bone = temp_bones_[roots[i]];
|
||||
bones_node->mChildren[i] = root_bone.node;
|
||||
build_bone_children_hierarchy(root_bone);
|
||||
}
|
||||
}
|
||||
|
||||
void HL1MDLLoader::build_bone_children_hierarchy(const TempBone &bone)
|
||||
{
|
||||
if (bone.children.empty())
|
||||
return;
|
||||
|
||||
aiNode* bone_node = bone.node;
|
||||
bone_node->mNumChildren = static_cast<unsigned int>(bone.children.size());
|
||||
bone_node->mChildren = new aiNode *[bone_node->mNumChildren];
|
||||
|
||||
// Build each child bone's hierarchy recursively.
|
||||
for (size_t i = 0; i < bone.children.size(); ++i)
|
||||
{
|
||||
const TempBone &child_bone = temp_bones_[bone.children[i]];
|
||||
bone_node->mChildren[i] = child_bone.node;
|
||||
build_bone_children_hierarchy(child_bone);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -143,6 +143,14 @@ private:
|
|||
*/
|
||||
static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
|
||||
|
||||
/**
|
||||
* \brief Build a bone's node children hierarchy.
|
||||
*
|
||||
* \param[in] bone The bone for which we must build all children hierarchy.
|
||||
*/
|
||||
struct TempBone;
|
||||
void build_bone_children_hierarchy(const TempBone& bone);
|
||||
|
||||
/** Output scene to be filled */
|
||||
aiScene *scene_;
|
||||
|
||||
|
@ -198,11 +206,13 @@ private:
|
|||
TempBone() :
|
||||
node(nullptr),
|
||||
absolute_transform(),
|
||||
offset_matrix() {}
|
||||
offset_matrix(),
|
||||
children() {}
|
||||
|
||||
aiNode *node;
|
||||
aiMatrix4x4 absolute_transform;
|
||||
aiMatrix4x4 offset_matrix;
|
||||
std::vector<int> children; // Bone children
|
||||
};
|
||||
|
||||
std::vector<TempBone> temp_bones_;
|
||||
|
|
|
@ -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
|
||||
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 "
|
||||
"or contains invalid data.");
|
||||
}
|
||||
|
@ -284,7 +290,7 @@ void MDLImporter::SizeCheck(const void *szPos) {
|
|||
// Just for debugging purposes
|
||||
void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
|
||||
ai_assert(nullptr != szFile);
|
||||
if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) {
|
||||
if (!IsPosValid(szPos)) {
|
||||
// remove a directory if there is one
|
||||
const char *szFilePtr = ::strrchr(szFile, '\\');
|
||||
if (!szFilePtr) {
|
||||
|
@ -975,7 +981,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones)
|
|||
}
|
||||
|
||||
// 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);
|
||||
pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Import a CS:S/HL2 MDL file (not fully implemented)
|
||||
*/
|
||||
void InternReadFile_HL2( );
|
||||
AI_WONT_RETURN void InternReadFile_HL2( ) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Check whether a given position is inside the valid range
|
||||
|
@ -150,6 +150,7 @@ protected:
|
|||
*/
|
||||
void SizeCheck(const void* szPos);
|
||||
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
|
||||
|
|
|
@ -470,7 +470,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
ASSIMP_LOG_ERROR("Found a reference to an embedded DDS texture, but texture width is zero, aborting import.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
pcNew.reset(new aiTexture);
|
||||
pcNew->mHeight = 0;
|
||||
pcNew->mWidth = iWidth;
|
||||
|
@ -481,6 +481,8 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
pcNew->achFormatHint[2] = 's';
|
||||
pcNew->achFormatHint[3] = '\0';
|
||||
|
||||
SizeCheck(szCurrent + pcNew->mWidth);
|
||||
|
||||
pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
|
||||
memcpy(pcNew->pcData, szCurrent, pcNew->mWidth);
|
||||
szCurrent += iWidth;
|
||||
|
@ -493,12 +495,12 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
|
||||
aiString szFile;
|
||||
const size_t iLen = strlen((const char *)szCurrent);
|
||||
size_t iLen2 = iLen + 1;
|
||||
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
|
||||
size_t iLen2 = iLen > (MAXLEN - 1) ? (MAXLEN - 1) : iLen;
|
||||
memcpy(szFile.data, (const char *)szCurrent, iLen2);
|
||||
szFile.data[iLen2] = '\0';
|
||||
szFile.length = static_cast<ai_uint32>(iLen2);
|
||||
|
||||
szCurrent += iLen2;
|
||||
szCurrent += iLen2 + 1;
|
||||
|
||||
// place this as diffuse texture
|
||||
pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
@ -703,7 +705,14 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7(
|
|||
tex.pcData = bad_texel;
|
||||
tex.mHeight = iHeight;
|
||||
tex.mWidth = iWidth;
|
||||
ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
|
||||
|
||||
try {
|
||||
ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
|
||||
} catch (...) {
|
||||
// FIX: Important, otherwise the destructor will crash
|
||||
tex.pcData = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
// FIX: Important, otherwise the destructor will crash
|
||||
tex.pcData = nullptr;
|
||||
|
|
|
@ -269,7 +269,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
|
|||
dynamic_cast<pmx::PmxVertexSkinningSDEF *>(v->skinning.get());
|
||||
switch (v->skinning_type) {
|
||||
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;
|
||||
case pmx::PmxVertexSkinningType::BDEF2:
|
||||
bone_vertex_map[vsBDEF2_ptr->bone_index1].emplace_back(index, vsBDEF2_ptr->bone_weight);
|
||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <assimp/types.h>
|
||||
#include "MMDCpp14.h"
|
||||
|
||||
namespace pmx
|
||||
|
@ -730,7 +731,7 @@ namespace pmx
|
|||
std::unique_ptr<PmxAncherRigidBody []> anchers;
|
||||
int pin_vertex_count;
|
||||
std::unique_ptr<int []> pin_vertices;
|
||||
void Read(std::istream *stream, PmxSetting *setting);
|
||||
AI_WONT_RETURN void Read(std::istream *stream, PmxSetting *setting) AI_WONT_RETURN_SUFFIX;
|
||||
};
|
||||
|
||||
class PmxModel
|
||||
|
|
|
@ -486,7 +486,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
for (unsigned int j = 0,n = 0; j < m->mNumFaces; ++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");
|
||||
}
|
||||
|
||||
|
@ -494,7 +494,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
|
|||
f.mIndices = new unsigned int[f.mNumIndices=3];
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <map>
|
||||
#include <limits>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -160,6 +161,9 @@ void NDOImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
|
||||
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 */
|
||||
|
||||
obj.name = std::string(head, temp);
|
||||
|
|
|
@ -107,7 +107,7 @@ private:
|
|||
|
||||
aiColor3D color, diffuse, specular, ambient, emissive;
|
||||
ai_real refracti;
|
||||
std::string texFile;
|
||||
std::string texFile;
|
||||
bool twoSided; // For NFF2
|
||||
bool shaded;
|
||||
ai_real opacity, shininess;
|
||||
|
|
|
@ -284,7 +284,7 @@ void OFFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
for (unsigned int i = 0; i < numFaces; ) {
|
||||
if(!GetNextLine(buffer,line)) {
|
||||
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;
|
||||
sz = line; SkipSpaces(&sz);
|
||||
|
|
|
@ -239,8 +239,6 @@ struct Mesh {
|
|||
unsigned int m_uiMaterialIndex;
|
||||
/// True, if normals are stored.
|
||||
bool m_hasNormals;
|
||||
/// True, if vertex colors are stored.
|
||||
bool m_hasVertexColors;
|
||||
|
||||
/// Constructor
|
||||
explicit Mesh(const std::string &name) :
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
Copyright (c) 2006-2023, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
@ -84,7 +84,6 @@ ObjFileImporter::ObjFileImporter() :
|
|||
// Destructor.
|
||||
ObjFileImporter::~ObjFileImporter() {
|
||||
delete m_pRootObject;
|
||||
m_pRootObject = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -270,7 +269,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
|
|||
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
|
||||
unsigned int meshId = pObject->m_Meshes[i];
|
||||
aiMesh *pMesh = createTopology(pModel, pObject, meshId);
|
||||
if (pMesh) {
|
||||
if (pMesh != nullptr) {
|
||||
if (pMesh->mNumFaces > 0) {
|
||||
MeshArray.push_back(pMesh);
|
||||
} else {
|
||||
|
@ -331,7 +330,6 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
|
|||
|
||||
for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
|
||||
const ObjFile::Face *inp = pObjMesh->m_Faces[index];
|
||||
//ai_assert(nullptr != inp);
|
||||
|
||||
if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
|
||||
pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
|
||||
|
@ -500,6 +498,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
|
|||
|
||||
if (vertexIndex) {
|
||||
if (!last) {
|
||||
if (pMesh->mNumVertices <= newIndex + 1) {
|
||||
throw DeadlyImportError("OBJ: bad vertex index");
|
||||
}
|
||||
|
||||
pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
|
||||
if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
|
||||
pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
|
||||
|
|
|
@ -252,9 +252,9 @@ void ObjFileMtlImporter::load() {
|
|||
case 'a': // Anisotropy
|
||||
{
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
|
||||
if (m_pModel->mCurrentMaterial != nullptr)
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
|
@ -371,6 +371,7 @@ void ObjFileMtlImporter::getTexture() {
|
|||
if (m_pModel->mCurrentMaterial == nullptr) {
|
||||
m_pModel->mCurrentMaterial = new ObjFile::Material();
|
||||
m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material");
|
||||
m_pModel->mMaterialMap["Empty_Material"] = m_pModel->mCurrentMaterial;
|
||||
}
|
||||
|
||||
const char *pPtr(&(*m_DataIt));
|
||||
|
@ -514,16 +515,16 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString
|
|||
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
getFloat(it, m_DataItEnd, m_pModel->mCurrentMaterial->bump_multiplier);
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, BlendUOption, static_cast<unsigned int>(strlen(BlendUOption))) ||
|
||||
} else if (!ASSIMP_strincmp(pPtr, BlendUOption, static_cast<unsigned int>(strlen(BlendUOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, BlendVOption, static_cast<unsigned int>(strlen(BlendVOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, BoostOption, static_cast<unsigned int>(strlen(BoostOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, ResolutionOption, static_cast<unsigned int>(strlen(ResolutionOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, BoostOption, static_cast<unsigned int>(strlen(BoostOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, ResolutionOption, static_cast<unsigned int>(strlen(ResolutionOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, ChannelOption, static_cast<unsigned int>(strlen(ChannelOption)))) {
|
||||
skipToken = 2;
|
||||
} else if (!ASSIMP_strincmp(pPtr, ModifyMapOption, static_cast<unsigned int>(strlen(ModifyMapOption)))) {
|
||||
skipToken = 3;
|
||||
} else if (!ASSIMP_strincmp(pPtr, OffsetOption, static_cast<unsigned int>(strlen(OffsetOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, ScaleOption, static_cast<unsigned int>(strlen(ScaleOption))) ||
|
||||
} else if (!ASSIMP_strincmp(pPtr, OffsetOption, static_cast<unsigned int>(strlen(OffsetOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, ScaleOption, static_cast<unsigned int>(strlen(ScaleOption))) ||
|
||||
!ASSIMP_strincmp(pPtr, TurbulenceOption, static_cast<unsigned int>(strlen(TurbulenceOption)))) {
|
||||
skipToken = 4;
|
||||
}
|
||||
|
|
|
@ -156,9 +156,17 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||
// read in vertex definition (homogeneous coords)
|
||||
getHomogeneousVector3(m_pModel->mVertices);
|
||||
} 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
|
||||
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') {
|
||||
// read in texture coordinate ( 2D or 3D )
|
||||
++m_DataIt;
|
||||
|
@ -236,7 +244,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name == "cstype";
|
||||
goto pf_skip_line;
|
||||
} break;
|
||||
}
|
||||
|
||||
default: {
|
||||
pf_skip_line:
|
||||
|
@ -456,9 +464,20 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
|
|||
iPos = 0;
|
||||
} else {
|
||||
//OBJ USES 1 Base ARRAYS!!!!
|
||||
const char *token = &(*m_DataIt);
|
||||
const int iVal = ::atoi(token);
|
||||
|
||||
int iVal;
|
||||
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
|
||||
int tmp = iVal;
|
||||
if (iVal < 0) {
|
||||
|
|
|
@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns true, if the last entry of the buffer is reached.
|
||||
* @param[in] it Iterator of current position.
|
||||
* @param[in] end Iterator with end of buffer.
|
||||
|
@ -67,7 +67,7 @@ inline bool isEndOfBuffer(char_t it, char_t end) {
|
|||
return (it == end);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns next word separated by a space
|
||||
* @param[in] pBuffer Pointer to data buffer
|
||||
* @param[in] pEnd Pointer to end of buffer
|
||||
|
@ -85,7 +85,7 @@ inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) {
|
|||
return pBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns pointer a next token
|
||||
* @param[in] pBuffer Pointer to data buffer
|
||||
* @param[in] pEnd Pointer to end of buffer
|
||||
|
@ -102,7 +102,7 @@ inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) {
|
|||
return getNextWord(pBuffer, pEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Skips a line
|
||||
* @param[in] it Iterator set to current position
|
||||
* @param[in] end Iterator set to end of scratch buffer for readout
|
||||
|
@ -131,7 +131,7 @@ inline char_t skipLine(char_t it, char_t end, unsigned int &uiLine) {
|
|||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Get a name from the current line. Preserve space in the middle,
|
||||
* but trim it at the end.
|
||||
* @param[in] it set to current position
|
||||
|
@ -162,13 +162,13 @@ inline char_t getName(char_t it, char_t end, std::string &name) {
|
|||
std::string strName(pStart, &(*it));
|
||||
if (!strName.empty()) {
|
||||
name = strName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Get a name from the current line. Do not preserve space
|
||||
* in the middle, but trim it at the end.
|
||||
* @param it set to current position
|
||||
|
@ -202,11 +202,11 @@ inline char_t getNameNoSpace(char_t it, char_t end, std::string &name) {
|
|||
if (!strName.empty()) {
|
||||
name = strName;
|
||||
}
|
||||
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Get next word from given line
|
||||
* @param[in] it set to current position
|
||||
* @param[in] end set to end of scratch buffer for readout
|
||||
|
@ -230,7 +230,7 @@ inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length)
|
|||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Get next float from given line
|
||||
* @param[in] it set to current position
|
||||
* @param[in] end set to end of scratch buffer for readout
|
||||
|
|
|
@ -60,17 +60,17 @@ namespace Ogre {
|
|||
class OgreImporter : public BaseImporter {
|
||||
public:
|
||||
/// 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:
|
||||
/// 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.
|
||||
virtual const aiImporterDesc *GetInfo() const override;
|
||||
const aiImporterDesc *GetInfo() const override;
|
||||
|
||||
/// BaseImporter override.
|
||||
virtual void SetupProperties(const Importer *pImp) override;
|
||||
void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
private:
|
||||
/// Read materials referenced by the @c mesh to @c pScene.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue