Merge branch 'master' into master

pull/5360/head
Kim Kulling 2023-12-18 20:45:18 +01:00 committed by GitHub
commit 03b78ed183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1119 changed files with 167369 additions and 47495 deletions

View File

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

View File

@ -46,7 +46,7 @@ jobs:
toolchain: ninja-vs-win64-cxx17 toolchain: ninja-vs-win64-cxx17
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
@ -69,17 +69,11 @@ jobs:
- name: Checkout Hunter toolchains - name: Checkout Hunter toolchains
if: endsWith(matrix.name, 'hunter') if: endsWith(matrix.name, 'hunter')
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
repository: cpp-pm/polly repository: cpp-pm/polly
path: cmake/polly path: cmake/polly
- name: Remove contrib directory for Hunter builds
if: contains(matrix.name, 'hunter')
uses: JesseTG/rm@v1.0.3
with:
path: contrib
- name: Cache DX SDK - name: Cache DX SDK
id: dxcache id: dxcache
if: contains(matrix.name, 'windows') if: contains(matrix.name, 'windows')

View File

@ -14,7 +14,7 @@ jobs:
name: adress-sanitizer name: adress-sanitizer
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1 - uses: lukka/set-shell-env@v1
with: with:
@ -38,7 +38,7 @@ jobs:
name: undefined-behavior-sanitizer name: undefined-behavior-sanitizer
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1 - uses: lukka/set-shell-env@v1
with: with:
@ -46,7 +46,7 @@ jobs:
CC: clang CC: clang
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v2 uses: lukka/run-cmake@v3
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
@ -57,3 +57,13 @@ jobs:
- name: test - name: test
run: cd build/bin && ./unit run: cd build/bin && ./unit
shell: bash shell: bash
job3:
name: printf-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: run scan_printf script
run: ./scripts/scan_printf.sh
shell: bash

View File

@ -43,6 +43,7 @@ cd assimp
cmake CMakeLists.txt cmake CMakeLists.txt
cmake --build . cmake --build .
``` ```
Note that by default this builds a shared library into the `bin` directory. If you want to build it as a static library see the build options at the bottom of this file.
### Build instructions for Windows with Visual-Studio ### Build instructions for Windows with Visual-Studio

View File

@ -49,14 +49,13 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.24.18.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd" SHA1 "1292e4d661e1770d6d6ca08c12c07cf34a0bf718"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
ENDIF() ENDIF()
PROJECT(Assimp VERSION 5.2.5) PROJECT(Assimp VERSION 5.3.0)
# All supported options ############################################### # All supported options ###############################################
@ -84,10 +83,6 @@ OPTION( ASSIMP_NO_EXPORT
"Disable Assimp's export functionality." "Disable Assimp's export functionality."
OFF OFF
) )
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
OFF
)
OPTION( ASSIMP_BUILD_ASSIMP_TOOLS OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
"If the supplementary tools for Assimp are built in addition to the library." "If the supplementary tools for Assimp are built in addition to the library."
OFF OFF
@ -134,6 +129,18 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF OFF
) )
IF (WIN32)
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
ON
)
ELSE()
OPTION( ASSIMP_BUILD_ZLIB
"Build your own zlib"
ON
)
ENDIF()
IF (WIN32) IF (WIN32)
# Use subset of Windows.h # Use subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
@ -193,12 +200,9 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER
SET (ASSIMP_SOVERSION 5) SET (ASSIMP_SOVERSION 5)
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
if(NOT ASSIMP_HUNTER_ENABLED) set(CMAKE_CXX_STANDARD 17)
# Enable C++17 support globally set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)
endif()
IF(NOT ASSIMP_IGNORE_GIT_HASH) IF(NOT ASSIMP_IGNORE_GIT_HASH)
# Get the current working branch # Get the current working branch
@ -246,8 +250,7 @@ IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
IF( ${OPERATING_SYSTEM} MATCHES "Android") IF(NOT ${OPERATING_SYSTEM} MATCHES "Android")
ELSE()
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 ) ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF() ENDIF()
@ -255,11 +258,15 @@ IF( UNIX )
ENDIF() ENDIF()
# Grouped compiler settings ######################################## # Grouped compiler settings ########################################
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW) IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU)
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON) SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF() ENDIF()
IF(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)
MESSAGE(STATUS "GCC13 detected disabling \"-Wdangling-reference\" in Cpp files as it appears to be a false positive")
ADD_COMPILE_OPTIONS("$<$<COMPILE_LANGUAGE:CXX>:-Wno-dangling-reference>")
ENDIF()
# hide all not-exported symbols # hide all not-exported symbols
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" ) IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
@ -273,9 +280,9 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
ELSEIF(MSVC) ELSEIF(MSVC)
# enable multi-core compilation with MSVC # enable multi-core compilation with MSVC
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX ) ADD_COMPILE_OPTIONS(/bigobj)
ELSE() # msvc ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX) ADD_COMPILE_OPTIONS(/MP /bigobj)
ENDIF() ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
@ -289,7 +296,6 @@ ELSEIF(MSVC)
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF") SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON) SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" ) SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
@ -314,17 +320,17 @@ ENDIF()
IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED) IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
IF (CMAKE_BUILD_TYPE STREQUAL "Debug") IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
ELSE() ELSE()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
# Experimental for pdb generation
ENDIF() ENDIF()
ENDIF() ENDIF()
IF (ASSIMP_COVERALLS) IF (ASSIMP_COVERALLS)
MESSAGE(STATUS "Coveralls enabled") MESSAGE(STATUS "Coveralls enabled")
INCLUDE(Coveralls) INCLUDE(Coveralls)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
@ -332,14 +338,16 @@ ENDIF()
IF (ASSIMP_ASAN) IF (ASSIMP_ASAN)
MESSAGE(STATUS "AddressSanitizer enabled") MESSAGE(STATUS "AddressSanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
ENDIF() ENDIF()
IF (ASSIMP_UBSAN) IF (ASSIMP_UBSAN)
MESSAGE(STATUS "Undefined Behavior sanitizer enabled") MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
ENDIF() ENDIF()
INCLUDE (FindPkgMacros) INCLUDE (FindPkgMacros)
@ -660,13 +668,13 @@ ELSE()
set_target_properties(draco_encoder draco_decoder PROPERTIES set_target_properties(draco_encoder draco_decoder PROPERTIES
EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_ALL TRUE
EXCLUDE_FROM_DEFAULT_BUILD TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE
) )
# Do build the draco shared library # Do build the draco shared library
set_target_properties(${draco_LIBRARIES} PROPERTIES set_target_properties(${draco_LIBRARIES} PROPERTIES
EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_ALL FALSE
EXCLUDE_FROM_DEFAULT_BUILD FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE
) )
TARGET_USE_COMMON_OUTPUT_DIRECTORY(${draco_LIBRARIES}) TARGET_USE_COMMON_OUTPUT_DIRECTORY(${draco_LIBRARIES})
TARGET_USE_COMMON_OUTPUT_DIRECTORY(draco_encoder) TARGET_USE_COMMON_OUTPUT_DIRECTORY(draco_encoder)
@ -683,8 +691,7 @@ ELSE()
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
COMPONENT ${LIBASSIMP_COMPONENT} COMPONENT ${LIBASSIMP_COMPONENT}
INCLUDES DESTINATION include INCLUDES DESTINATION include
) )
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDIF() ENDIF()
@ -770,7 +777,7 @@ IF ( ASSIMP_INSTALL )
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" ) SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS) SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
SET(cPACK_DEBIAN_PACKAGE_NAME "assimp") SET(CPACK_DEBIAN_PACKAGE_NAME "assimp")
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging) SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
SET(CPACK_DEBIAN_CHANGELOG) SET(CPACK_DEBIAN_CHANGELOG)

128
CODE_OF_CONDUCT.md 100644
View File

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

View File

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

View File

@ -1,42 +1,41 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
================================== ==================================
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
### Current project status ### ### Current project status ###
[![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp)
![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg) ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
<a href="https://scan.coverity.com/projects/5607">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5607/badge.svg"/>
</a>
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade)
[![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master)
[![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open") [![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
<br> <br>
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. Additionally, assimp features various __mesh post-processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
### Latest Doc's ### ### Documentation ###
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).
### Get involved ### ### Pre-built binaries ###
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib)
<br>
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
<br>
Please check our Wiki as well: https://github.com/assimp/assimp/wiki
If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
### Communities ###
- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions)
- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/)
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
#### Supported file formats #### #### Supported file formats ####
You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md)
### Building ### ### Building ###
Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do. Take a look [here](https://github.com/assimp/assimp/blob/master/Build.md) to get started. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do.
### Ports ### ### Ports ###
* [Android](port/AndroidJNI/README.md) * [Android](port/AndroidJNI/README.md)
@ -53,40 +52,31 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
### Other tools ### ### Other tools ###
[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
[Assimp-Viewer](https://github.com/assimp/assimp_view) is an experimental implementation for an Asset-Viewer based on ImGUI and Assimp (experimental).
#### Repository structure #### #### Repository structure ####
Open Asset Import Library is implemented in C++. The directory structure looks like: Open Asset Import Library is implemented in C++. The directory structure looks like this:
/code Source code /code Source code
/contrib Third-party libraries /contrib Third-party libraries
/doc Documentation (doxysource and pre-compiled docs) /doc Documentation (doxysource and pre-compiled docs)
/fuzz Contains the test-code for the Google-Fuzzer project /fuzz Contains the test code for the Google Fuzzer project
/include Public header C and C++ header files /include Public header C and C++ header files
/scripts Scripts used to generate the loading code for some formats /scripts Scripts are used to generate the loading code for some formats
/port Ports to other languages and scripts to maintain those. /port Ports to other languages and scripts to maintain those.
/test Unit- and regression tests, test suite of models /test Unit- and regression tests, test suite of models
/tools Tools (old assimp viewer, command line `assimp`) /tools Tools (old assimp viewer, command line `assimp`)
/samples A small number of samples to illustrate possible /samples A small number of samples to illustrate possible use cases for Assimp
use cases for Assimp
The source code is organized in the following way: The source code is organized in the following way:
code/Common The base implementation for importers and the infrastructure code/Common The base implementation for importers and the infrastructure
code/CApi Special implementations which are only used for the C-API
code/Geometry A collection of geometry tools
code/Material The material system
code/PBR An exporter for physical-based models
code/PostProcessing The post-processing steps code/PostProcessing The post-processing steps
code/AssetLib/<FormatName> Implementation for import and export for the format code/AssetLib/<FormatName> Implementation for import and export of the format
### Where to get help ###
To find our documentation, visit [our website](https://assimp.org/) or check out [Wiki](https://github.com/assimp/assimp/wiki)
If the docs don't solve your problem, you can:
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/)
- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions)
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
### Contributing ### ### Contributing ###
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
@ -123,4 +113,4 @@ and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you ma
For the legal details, see the `LICENSE` file. For the legal details, see the `LICENSE` file.
### Why this name ### ### Why this name ###
Sorry, we're germans :-), no english native speakers ... Sorry, we're germans :-), no English native speakers ...

View File

@ -52,9 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cctype> #include <cctype>
#include <memory> #include <memory>
using namespace Assimp; namespace Assimp {
static const unsigned int NotSet = 0xcdcdcdcd; static constexpr unsigned int NotSet = 0xcdcdcdcd;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup final material indices, generae a default material if necessary // Setup final material indices, generae a default material if necessary
@ -68,7 +68,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
unsigned int idx(NotSet); unsigned int idx(NotSet);
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) { for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
std::string s = mScene->mMaterials[i].mName; std::string s = mScene->mMaterials[i].mName;
for (char & it : s) { for (char &it : s) {
it = static_cast<char>(::tolower(static_cast<unsigned char>(it))); it = static_cast<char>(::tolower(static_cast<unsigned char>(it)));
} }
@ -262,7 +262,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
unsigned int iWire = 1; unsigned int iWire = 1;
mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME); mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
} }
[[fallthrough]]; [[fallthrough]];
case D3DS::Discreet3DS::Gouraud: case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; eShading = aiShadingMode_Gouraud;
@ -593,7 +593,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
// Cameras or lights define their transformation in their parent node and in the // Cameras or lights define their transformation in their parent node and in the
// corresponding light or camera chunks. However, we read and process the latter // corresponding light or camera chunks. However, we read and process the latter
// to to be able to return valid cameras/lights even if no scenegraph is given. // to be able to return valid cameras/lights even if no scenegraph is given.
for (unsigned int n = 0; n < pcSOut->mNumCameras; ++n) { for (unsigned int n = 0; n < pcSOut->mNumCameras; ++n) {
if (pcSOut->mCameras[n]->mName == pcOut->mName) { if (pcSOut->mCameras[n]->mName == pcOut->mName) {
pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f, 0.f, 1.f); pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f, 0.f, 1.f);
@ -805,4 +805,6 @@ void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
} }
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -57,8 +56,7 @@ struct aiNode;
struct aiMaterial; struct aiMaterial;
struct aiMesh; struct aiMesh;
namespace Assimp namespace Assimp {
{
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/** /**
@ -88,7 +86,7 @@ private:
std::map<const aiNode*, aiMatrix4x4> trafos; std::map<const aiNode*, aiMatrix4x4> trafos;
typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap; using MeshesByNodeMap = std::multimap<const aiNode*, unsigned int>;
MeshesByNodeMap meshes; MeshesByNodeMap meshes;
}; };

View File

@ -397,10 +397,6 @@ struct Material {
Material(const Material &other) = default; Material(const Material &other) = default;
Material(Material &&other) AI_NO_EXCEPT = default;
Material &operator=(Material &&other) AI_NO_EXCEPT = default;
virtual ~Material() = default; virtual ~Material() = default;
//! Name of the material //! Name of the material

View File

@ -54,9 +54,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
using namespace Assimp; namespace Assimp {
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Discreet 3DS Importer", "Discreet 3DS Importer",
"", "",
"", "",
@ -103,10 +103,6 @@ Discreet3DSImporter::Discreet3DSImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
Discreet3DSImporter::~Discreet3DSImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -266,8 +262,15 @@ void Discreet3DSImporter::ParseMainChunk() {
}; };
ASSIMP_3DS_END_CHUNK(); ASSIMP_3DS_END_CHUNK();
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code-return"
#endif
// recursively continue processing this hierarchy level // recursively continue processing this hierarchy level
return ParseMainChunk(); return ParseMainChunk();
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -362,7 +365,7 @@ void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
// IMPLEMENTATION NOTE; // IMPLEMENTATION NOTE;
// Cameras or lights define their transformation in their parent node and in the // Cameras or lights define their transformation in their parent node and in the
// corresponding light or camera chunks. However, we read and process the latter // corresponding light or camera chunks. However, we read and process the latter
// to to be able to return valid cameras/lights even if no scenegraph is given. // to be able to return valid cameras/lights even if no scenegraph is given.
// get chunk type // get chunk type
switch (chunk.Flag) { switch (chunk.Flag) {
@ -1332,4 +1335,6 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
(void)bGamma; (void)bGamma;
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

View File

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

View File

@ -93,7 +93,7 @@ public:
// empty // empty
} }
~EmbeddedTexture() = default; ~EmbeddedTexture() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_EmbeddedTexture2D; return ResourceType::RT_EmbeddedTexture2D;
@ -110,7 +110,7 @@ public:
// empty // empty
} }
~Texture2DGroup() = default; ~Texture2DGroup() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_Texture2DGroup; return ResourceType::RT_Texture2DGroup;
@ -127,7 +127,7 @@ public:
// empty // empty
} }
~BaseMaterials() = default; ~BaseMaterials() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_BaseMaterials; return ResourceType::RT_BaseMaterials;
@ -152,7 +152,7 @@ public:
// empty // empty
} }
~Object() = default; ~Object() override = default;
ResourceType getType() const override { ResourceType getType() const override {
return ResourceType::RT_Object; return ResourceType::RT_Object;

View File

@ -68,7 +68,7 @@ namespace Assimp {
using namespace D3MF; using namespace D3MF;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"3mf Importer", "3mf Importer",
"", "",
"", "",
@ -81,10 +81,6 @@ static const aiImporterDesc desc = {
"3mf" "3mf"
}; };
D3MFImporter::D3MFImporter() = default;
D3MFImporter::~D3MFImporter() = default;
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const { bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const {
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false; return false;

View File

@ -56,10 +56,10 @@ namespace Assimp {
class D3MFImporter : public BaseImporter { class D3MFImporter : public BaseImporter {
public: public:
/// @brief The default class constructor. /// @brief The default class constructor.
D3MFImporter(); D3MFImporter() = default;
/// @brief The class destructor. /// @brief The class destructor.
~D3MFImporter() override; ~D3MFImporter() override = default;
/// @brief Performs the data format detection. /// @brief Performs the data format detection.
/// @param pFile The filename to check. /// @param pFile The filename to check.

View File

@ -68,7 +68,7 @@ using OpcPackageRelationshipPtr = std::shared_ptr<OpcPackageRelationship>;
class OpcPackageRelationshipReader { class OpcPackageRelationshipReader {
public: public:
OpcPackageRelationshipReader(XmlParser &parser) : OpcPackageRelationshipReader(XmlParser &parser) :
m_relationShips() { mRelations() {
XmlNode root = parser.getRootNode(); XmlNode root = parser.getRootNode();
ParseRootNode(root); ParseRootNode(root);
} }
@ -108,13 +108,13 @@ public:
relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE).as_string(); relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE).as_string();
relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET).as_string(); relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET).as_string();
if (validateRels(relPtr)) { if (validateRels(relPtr)) {
m_relationShips.push_back(relPtr); mRelations.push_back(relPtr);
} }
} }
} }
} }
std::vector<OpcPackageRelationshipPtr> m_relationShips; std::vector<OpcPackageRelationshipPtr> mRelations;
}; };
static bool IsEmbeddedTexture( const std::string &filename ) { static bool IsEmbeddedTexture( const std::string &filename ) {
@ -186,9 +186,6 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
D3MFOpcPackage::~D3MFOpcPackage() { D3MFOpcPackage::~D3MFOpcPackage() {
mZipArchive->Close(mRootStream); mZipArchive->Close(mRootStream);
delete mZipArchive; delete mZipArchive;
for (auto tex : mEmbeddedTextures) {
delete tex;
}
} }
IOStream *D3MFOpcPackage::RootStream() const { IOStream *D3MFOpcPackage::RootStream() const {
@ -217,11 +214,11 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
OpcPackageRelationshipReader reader(xmlParser); OpcPackageRelationshipReader reader(xmlParser);
auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) { auto itr = std::find_if(reader.mRelations.begin(), reader.mRelations.end(), [](const OpcPackageRelationshipPtr &rel) {
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
}); });
if (itr == reader.m_relationShips.end()) { if (itr == reader.mRelations.end()) {
throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
} }

View File

@ -49,12 +49,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
static const int IdNotSet = -1; static constexpr int IdNotSet = -1;
namespace { namespace {
static const size_t ColRGBA_Len = 9; static constexpr size_t ColRGBA_Len = 9;
static const size_t ColRGB_Len = 7; static constexpr size_t ColRGB_Len = 7;
// format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1) // format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
bool validateColorString(const char *color) { bool validateColorString(const char *color) {

View File

@ -60,9 +60,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <memory> #include <memory>
using namespace Assimp; namespace Assimp {
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"AC3D Importer", "AC3D Importer",
"", "",
"", "",
@ -866,4 +866,6 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
} }
} }
} // namespace Assimp
#endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER

View File

@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
const aiImporterDesc AMFImporter::Description = { static constexpr aiImporterDesc Description = {
"Additive manufacturing file format(AMF) Importer", "Additive manufacturing file format(AMF) Importer",
"smalcom", "smalcom",
"", "",

View File

@ -98,8 +98,12 @@ namespace Assimp {
/// old - <map> and children <u1>, <u2>, <u3>, <v1>, <v2>, <v3> /// old - <map> and children <u1>, <u2>, <u3>, <v1>, <v2>, <v3>
/// ///
class AMFImporter : public BaseImporter { class AMFImporter : public BaseImporter {
private: using AMFMetaDataArray = std::vector<AMFMetadata *>;
struct SPP_Material; // forward declaration using MeshArray = std::vector<aiMesh *>;
using NodeArray = std::vector<aiNode *>;
public:
struct SPP_Material;
/// Data type for post-processing step. More suitable container for part of material's composition. /// Data type for post-processing step. More suitable container for part of material's composition.
struct SPP_Composite { struct SPP_Composite {
@ -107,22 +111,6 @@ private:
std::string Formula; ///< Formula for calculating ratio of \ref Material. std::string Formula; ///< Formula for calculating ratio of \ref Material.
}; };
/// \struct SPP_Material
/// Data type for post-processing step. More suitable container for material.
struct SPP_Material {
std::string ID; ///< Material ID.
std::list<AMFMetadata *> Metadata; ///< Metadata of material.
AMFColor *Color; ///< Color of material.
std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate.
/// \param [in] pX - "x" coordinate.
/// \param [in] pY - "y" coordinate.
/// \param [in] pZ - "z" coordinate.
/// \return calculated color.
aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
};
/// Data type for post-processing step. More suitable container for texture. /// Data type for post-processing step. More suitable container for texture.
struct SPP_Texture { struct SPP_Texture {
std::string ID; std::string ID;
@ -139,10 +127,52 @@ private:
const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
}; };
using AMFMetaDataArray = std::vector<AMFMetadata*>; /// Data type for post-processing step. More suitable container for material.
using MeshArray = std::vector<aiMesh*>; struct SPP_Material {
using NodeArray = std::vector<aiNode*>; std::string ID; ///< Material ID.
std::list<AMFMetadata *> Metadata; ///< Metadata of material.
AMFColor *Color; ///< Color of material.
std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate.
/// \param [in] pX - "x" coordinate.
/// \param [in] pY - "y" coordinate.
/// \param [in] pZ - "z" coordinate.
/// \return calculated color.
aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
};
/// Default constructor.
AMFImporter() AI_NO_EXCEPT;
/// Default destructor.
~AMFImporter() override;
/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
/// Also exception can be thrown if trouble will found.
/// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
void ParseHelper_Node_Enter(AMFNodeElementBase *child);
void ParseHelper_Node_Exit();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const override;
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
const aiImporterDesc *GetInfo() const override;
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;
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);
AMFImporter(const AMFImporter &pScene) = delete;
AMFImporter &operator=(const AMFImporter &pScene) = delete;
private:
/// Clear all temporary data. /// Clear all temporary data.
void Clear(); void Clear();
@ -262,40 +292,9 @@ private:
/// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>. /// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>.
void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false); void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false);
public:
/// Default constructor.
AMFImporter() AI_NO_EXCEPT;
/// Default destructor.
~AMFImporter() override;
/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
/// Also exception can be thrown if trouble will found.
/// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
void ParseHelper_Node_Enter(AMFNodeElementBase *child);
void ParseHelper_Node_Exit();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const override;
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
const aiImporterDesc *GetInfo() const override;
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;
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
bool XML_SearchNode(const std::string &nodeName);
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
AMFImporter(const AMFImporter &pScene) = delete;
AMFImporter &operator=(const AMFImporter &pScene) = delete;
private: private:
static const aiImporterDesc Description;
AMFNodeElementBase *mNodeElement_Cur; ///< Current element. AMFNodeElementBase *mNodeElement_Cur; ///< Current element.
std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph. std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph.
XmlParser *mXmlParser; XmlParser *mXmlParser;

View File

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

View File

@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers // internal headers
@ -64,10 +63,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// utilities // utilities
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
using namespace Assimp; namespace Assimp {
using namespace Assimp::ASE; using namespace Assimp::ASE;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"ASE Importer", "ASE Importer",
"", "",
"", "",
@ -322,21 +321,6 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); aiNodeAnim *nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nd->mNodeName.Set(me->mName + ".Target"); nd->mNodeName.Set(me->mName + ".Target");
// If there is no input position channel we will need
// to supply the default position from the node's
// local transformation matrix.
/*TargetAnimationHelper helper;
if (me->mAnim.akeyPositions.empty())
{
aiMatrix4x4& mat = (*i)->mTransform;
helper.SetFixedMainAnimationChannel(aiVector3D(
mat.a4, mat.b4, mat.c4));
}
else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
helper.Process(&me->mTargetAnim.akeyPositions);*/
// Allocate the key array and fill it // Allocate the key array and fill it
nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size(); nd->mNumPositionKeys = (unsigned int)me->mTargetAnim.akeyPositions.size();
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
@ -920,7 +904,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMes
ASSIMP_LOG_WARN("Material index is out of range"); ASSIMP_LOG_WARN("Material index is out of range");
} }
// If the material the mesh is assigned to is consisting of submeshes, split it // If the material the mesh is assigned to consists of submeshes, split it
if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) { if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials; std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
@ -1278,6 +1262,8 @@ bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) {
return false; return false;
} }
}
#endif // ASSIMP_BUILD_NO_3DS_IMPORTER #endif // ASSIMP_BUILD_NO_3DS_IMPORTER
#endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER

View File

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

View File

@ -50,11 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/version.h> #include <assimp/version.h>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB #include "zlib.h"
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif
#include <ctime> #include <ctime>

View File

@ -65,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Assimp Binary Importer", "Assimp Binary Importer",
"Gargaj / Conspiracy", "Gargaj / Conspiracy",
"", "",

View File

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

View File

@ -59,10 +59,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
using namespace Assimp; namespace Assimp {
using namespace std; using namespace std;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"BlitzBasic 3D Importer", "BlitzBasic 3D Importer",
"", "",
"", "",
@ -79,9 +79,9 @@ static const aiImporterDesc desc = {
#pragma warning(disable : 4018) #pragma warning(disable : 4018)
#endif #endif
//#define DEBUG_B3D // #define DEBUG_B3D
template<typename T> template <typename T>
void DeleteAllBarePointers(std::vector<T> &x) { void DeleteAllBarePointers(std::vector<T> &x) {
for (auto p : x) { for (auto p : x) {
delete p; delete p;
@ -150,7 +150,7 @@ AI_WONT_RETURN void B3DImporter::Fail(const string &str) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte() { int B3DImporter::ReadByte() {
if (_pos > _buf.size()) { if (_pos >= _buf.size()) {
Fail("EOF"); Fail("EOF");
} }
@ -329,7 +329,7 @@ void B3DImporter::ReadBRUS() {
mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
} }
//Textures // Textures
for (int i = 0; i < n_texs; ++i) { for (int i = 0; i < n_texs; ++i) {
int texid = ReadInt(); int texid = ReadInt();
if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) { if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) {
@ -372,7 +372,7 @@ void B3DImporter::ReadVRTS() {
} }
if (_vflags & 2) { if (_vflags & 2) {
ReadQuat(); //skip v 4bytes... ReadQuat(); // skip v 4bytes...
} }
for (int j = 0; j < _tcsets; ++j) { for (int j = 0; j < _tcsets; ++j) {
@ -418,7 +418,6 @@ void B3DImporter::ReadTRIS(int v0) {
ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2); ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
#endif #endif
Fail("Bad triangle index"); Fail("Bad triangle index");
continue;
} }
face->mNumIndices = 3; face->mNumIndices = 3;
face->mIndices = new unsigned[3]; face->mIndices = new unsigned[3];
@ -705,22 +704,22 @@ void B3DImporter::ReadBB3D(aiScene *scene) {
} }
} }
//nodes // nodes
scene->mRootNode = _nodes[0]; scene->mRootNode = _nodes[0];
_nodes.clear(); // node ownership now belongs to scene _nodes.clear(); // node ownership now belongs to scene
//material // material
if (!_materials.size()) { if (!_materials.size()) {
_materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial)); _materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial));
} }
scene->mNumMaterials = static_cast<unsigned int>(_materials.size()); scene->mNumMaterials = static_cast<unsigned int>(_materials.size());
scene->mMaterials = unique_to_array(_materials); scene->mMaterials = unique_to_array(_materials);
//meshes // meshes
scene->mNumMeshes = static_cast<unsigned int>(_meshes.size()); scene->mNumMeshes = static_cast<unsigned int>(_meshes.size());
scene->mMeshes = unique_to_array(_meshes); scene->mMeshes = unique_to_array(_meshes);
//animations // animations
if (_animations.size() == 1 && _nodeAnims.size()) { if (_animations.size() == 1 && _nodeAnims.size()) {
aiAnimation *anim = _animations.back().get(); aiAnimation *anim = _animations.back().get();
@ -739,4 +738,6 @@ void B3DImporter::ReadBB3D(aiScene *scene) {
flip.Execute(scene); flip.Execute(scene);
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

View File

@ -55,10 +55,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map> #include <map>
#include <memory> #include <memory>
using namespace Assimp; namespace Assimp {
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"BVH Importer (MoCap)", "BVH Importer (MoCap)",
"", "",
"", "",
@ -73,8 +74,8 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception // Aborts the file reading with an exception
template<typename... T> template <typename... T>
AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) { AI_WONT_RETURN void BVHLoader::ThrowException(T &&...args) {
throw DeadlyImportError(mFileName, ":", mLine, " - ", args...); throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
} }
@ -426,7 +427,7 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
nodeAnim->mNodeName.Set(nodeName); nodeAnim->mNodeName.Set(nodeName);
std::map<BVHLoader::ChannelType, int> channelMap; std::map<BVHLoader::ChannelType, int> channelMap;
//Build map of channels // Build map of channels
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) { for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
channelMap[node.mChannels[channel]] = channel; channelMap[node.mChannels[channel]] = channel;
} }
@ -441,7 +442,7 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
// Now compute all translations // Now compute all translations
for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) { for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
//Find channel in node // Find channel in node
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel); std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
if (mapIter == channelMap.end()) if (mapIter == channelMap.end())
@ -485,30 +486,27 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) { for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
aiMatrix4x4 temp; aiMatrix4x4 temp;
aiMatrix3x3 rotMatrix; aiMatrix3x3 rotMatrix;
for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) { for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++channelIdx) {
switch (node.mChannels[channelIdx]) { switch (node.mChannels[channelIdx]) {
case Channel_RotationX: case Channel_RotationX: {
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); aiMatrix4x4::RotationX(angle, temp);
} rotMatrix *= aiMatrix3x3(temp);
break; } break;
case Channel_RotationY: case Channel_RotationY: {
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); aiMatrix4x4::RotationY(angle, temp);
} rotMatrix *= aiMatrix3x3(temp);
break; } break;
case Channel_RotationZ: case Channel_RotationZ: {
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); aiMatrix4x4::RotationZ(angle, temp);
} rotMatrix *= aiMatrix3x3(temp);
break; } break;
default: default:
break; break;
} }
} }
rotkey->mTime = double(fr); rotkey->mTime = double(fr);
rotkey->mValue = aiQuaternion(rotMatrix); rotkey->mValue = aiQuaternion(rotMatrix);
++rotkey; ++rotkey;
@ -525,4 +523,6 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
} }
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER

View File

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

View File

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

View File

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

View File

@ -283,6 +283,11 @@ void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data,
if (conv_data.meshes->empty()) { if (conv_data.meshes->empty()) {
return; return;
} }
const size_t meshIndex = conv_data.meshes->size() - out.mNumMeshes;
if (meshIndex >= conv_data.meshes->size()) {
ASSIMP_LOG_ERROR("Invalid index detected.");
return;
}
aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes]; aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
std::unique_ptr<aiMesh *[]> tempmeshes(new aiMesh *[out.mNumMeshes]()); std::unique_ptr<aiMesh *[]> tempmeshes(new aiMesh *[out.mNumMeshes]());

View File

@ -102,10 +102,6 @@ void Structure::Convert<CollectionObject>(
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db); ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
{ {
//std::shared_ptr<CollectionObject> prev;
//ReadFieldPtr<ErrorPolicy_Fail>(prev, "*prev", db);
//dest.prev = prev.get();
std::shared_ptr<Object> ob; std::shared_ptr<Object> ob;
ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db); ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
dest.ob = ob.get(); dest.ob = ob.get();
@ -301,7 +297,7 @@ void Structure ::Convert<Base>(
const FileDatabase &db) const { const FileDatabase &db) const {
// note: as per https://github.com/assimp/assimp/issues/128, // note: as per https://github.com/assimp/assimp/issues/128,
// reading the Object linked list recursively is prone to stack overflow. // reading the Object linked list recursively is prone to stack overflow.
// This structure converter is therefore an hand-written exception that // This structure converter is therefore a hand-written exception that
// does it iteratively. // does it iteratively.
const int initial_pos = db.reader->GetCurrentPos(); const int initial_pos = db.reader->GetCurrentPos();
@ -569,7 +565,7 @@ void Structure ::Convert<MVert>(
const FileDatabase &db) const { const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db); ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db); ReadFieldArray<ErrorPolicy_Warn>(dest.no, "no", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db); ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
//ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db); //ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db); ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,10 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file BlenderTessellator.cpp /// @file BlenderTessellator.cpp
* @brief A simple tessellation wrapper /// @brief A simple tessellation wrapper
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -144,11 +143,7 @@ namespace Assimp
#if ASSIMP_BLEND_WITH_POLY_2_TRI #if ASSIMP_BLEND_WITH_POLY_2_TRI
#ifdef ASSIMP_USE_HUNTER #include "contrib/poly2tri/poly2tri/poly2tri.h"
# include <poly2tri/poly2tri.h>
#else
# include "../contrib/poly2tri/poly2tri/poly2tri.h"
#endif
namespace Assimp namespace Assimp
{ {

View File

@ -61,11 +61,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
using namespace Assimp; namespace Assimp {
using namespace Assimp::COB; using namespace Assimp::COB;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
static const float units[] = { static constexpr float units[] = {
1000.f, 1000.f,
100.f, 100.f,
1.f, 1.f,
@ -76,7 +76,7 @@ static const float units[] = {
1.f / 1609.344f 1.f / 1609.344f
}; };
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"TrueSpace Object Importer", "TrueSpace Object Importer",
"", "",
"", "",
@ -89,14 +89,6 @@ static const aiImporterDesc desc = {
"cob scn" "cob scn"
}; };
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
COBImporter::COBImporter() = default;
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
COBImporter::~COBImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -1172,4 +1164,6 @@ void COBImporter::ReadUnit_Binary(COB::Scene &out, StreamReaderLE &reader, const
ASSIMP_LOG_WARN("`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist"); ASSIMP_LOG_WARN("`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist");
} }
}
#endif // ASSIMP_BUILD_NO_COB_IMPORTER #endif // ASSIMP_BUILD_NO_COB_IMPORTER

View File

@ -56,16 +56,16 @@ class LineSplitter;
// TinyFormatter.h // TinyFormatter.h
namespace Formatter { namespace Formatter {
template <typename T, typename TR, typename A> template <typename T, typename TR, typename A>
class basic_formatter; class basic_formatter;
typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>> format; typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>> format;
} // namespace Formatter } // namespace Formatter
// COBScene.h // COBScene.h
namespace COB { namespace COB {
struct ChunkInfo; struct ChunkInfo;
struct Node; struct Node;
struct Scene; struct Scene;
} // namespace COB } // namespace COB
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
@ -75,8 +75,8 @@ struct Scene;
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class COBImporter : public BaseImporter { class COBImporter : public BaseImporter {
public: public:
COBImporter(); COBImporter() = default;
~COBImporter() override; ~COBImporter() override = default;
// -------------------- // --------------------
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool CanRead(const std::string &pFile, IOSystem *pIOHandler,

View File

@ -44,9 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file CSMLoader.cpp /** @file CSMLoader.cpp
* Implementation of the CSM importer class. * Implementation of the CSM importer class.
*/ */
#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
#include "CSMLoader.h" #include "CSMLoader.h"
@ -63,7 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"CharacterStudio Motion Importer (MoCap)", "CharacterStudio Motion Importer (MoCap)",
"", "",
"", "",
@ -79,13 +76,9 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
CSMImporter::CSMImporter() CSMImporter::CSMImporter() : noSkeletonMesh(){
: noSkeletonMesh() // empty
{} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
CSMImporter::~CSMImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.

View File

@ -61,7 +61,7 @@ namespace Assimp {
class CSMImporter : public BaseImporter { class CSMImporter : public BaseImporter {
public: public:
CSMImporter(); CSMImporter();
~CSMImporter() override; ~CSMImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
@ -81,9 +81,8 @@ protected:
private: private:
bool noSkeletonMesh; bool noSkeletonMesh;
}; // end of class CSMImporter };
} // end of namespace Assimp } // namespace Assimp
#endif // AI_AC3DIMPORTER_H_INC #endif // AI_AC3DIMPORTER_H_INC

View File

@ -64,7 +64,7 @@ namespace Assimp {
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
using namespace Assimp::Collada; using namespace Assimp::Collada;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Collada Importer", "Collada Importer",
"", "",
"", "",
@ -95,15 +95,12 @@ ColladaLoader::ColladaLoader() :
noSkeletonMesh(false), noSkeletonMesh(false),
removeEmptyBones(false), removeEmptyBones(false),
ignoreUpDirection(false), ignoreUpDirection(false),
ignoreUnitSize(false),
useColladaName(false), useColladaName(false),
mNodeNameCounter(0) { mNodeNameCounter(0) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ColladaLoader::~ColladaLoader() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -122,6 +119,7 @@ void ColladaLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0; removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
ignoreUnitSize = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UNIT_SIZE, 0) != 0;
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0; useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
} }
@ -170,12 +168,15 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// ... then fill the materials with the now adjusted settings // ... then fill the materials with the now adjusted settings
FillMaterials(parser, pScene); FillMaterials(parser, pScene);
// Apply unit-size scale calculation if (!ignoreUnitSize) {
// Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, pScene->mRootNode->mTransformation *= aiMatrix4x4(
0, parser.mUnitSize, 0, 0, parser.mUnitSize, 0, 0, 0,
0, 0, parser.mUnitSize, 0, 0, parser.mUnitSize, 0, 0,
0, 0, 0, 1); 0, 0, parser.mUnitSize, 0,
0, 0, 0, 1);
}
if (!ignoreUpDirection) { if (!ignoreUpDirection) {
// Convert to Y_UP, if different orientation // Convert to Y_UP, if different orientation
if (parser.mUpDirection == ColladaParser::UP_X) { if (parser.mUpDirection == ColladaParser::UP_X) {

View File

@ -86,7 +86,7 @@ public:
ColladaLoader(); ColladaLoader();
/// The class destructor. /// The class destructor.
~ColladaLoader() override; ~ColladaLoader() override = default;
/// Returns whether the class can handle the format of the given file. /// Returns whether the class can handle the format of the given file.
/// @see BaseImporter::CanRead() for more details. /// @see BaseImporter::CanRead() for more details.
@ -239,6 +239,7 @@ protected:
bool noSkeletonMesh; bool noSkeletonMesh;
bool removeEmptyBones; bool removeEmptyBones;
bool ignoreUpDirection; bool ignoreUpDirection;
bool ignoreUnitSize;
bool useColladaName; bool useColladaName;
/** Used by FindNameForNode() to generate unique node names */ /** Used by FindNameForNode() to generate unique node names */

View File

@ -814,38 +814,38 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
if (!pImage.mFileName.length()) { if (!pImage.mFileName.length()) {
pImage.mFileName = "unknown_texture"; pImage.mFileName = "unknown_texture";
} }
} } else if (mFormat == FV_1_5_n) {
} else if (mFormat == FV_1_5_n) { std::string value;
std::string value; XmlNode refChild = currentNode.child("ref");
XmlNode refChild = currentNode.child("ref"); XmlNode hexChild = currentNode.child("hex");
XmlNode hexChild = currentNode.child("hex"); if (refChild) {
if (refChild) { // element content is filename - hopefully
// element content is filename - hopefully if (XmlParser::getValueAsString(refChild, value)) {
if (XmlParser::getValueAsString(refChild, value)) { aiString filepath(value);
aiString filepath(value); UriDecodePath(filepath);
UriDecodePath(filepath); pImage.mFileName = filepath.C_Str();
pImage.mFileName = filepath.C_Str(); }
} } else if (hexChild && !pImage.mFileName.length()) {
} else if (hexChild && !pImage.mFileName.length()) { // embedded image. get format
// embedded image. get format pImage.mEmbeddedFormat = hexChild.attribute("format").as_string();
pImage.mEmbeddedFormat = hexChild.attribute("format").as_string(); if (pImage.mEmbeddedFormat.empty()) {
if (pImage.mEmbeddedFormat.empty()) { ASSIMP_LOG_WARN("Collada: Unknown image file format");
ASSIMP_LOG_WARN("Collada: Unknown image file format"); }
}
XmlParser::getValueAsString(hexChild, value); XmlParser::getValueAsString(hexChild, value);
const char *data = value.c_str(); const char *data = value.c_str();
// hexadecimal-encoded binary octets. First of all, find the // hexadecimal-encoded binary octets. First of all, find the
// required buffer size to reserve enough storage. // required buffer size to reserve enough storage.
const char *cur = data; const char *cur = data;
while (!IsSpaceOrNewLine(*cur)) { while (!IsSpaceOrNewLine(*cur)) {
++cur; ++cur;
} }
const unsigned int size = (unsigned int)(cur - data) * 2; const unsigned int size = (unsigned int)(cur - data) * 2;
pImage.mImageData.resize(size); pImage.mImageData.resize(size);
for (unsigned int i = 0; i < size; ++i) { for (unsigned int i = 0; i < size; ++i) {
pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1)); pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1));
}
} }
} }
} }
@ -1274,9 +1274,7 @@ void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam)
return; return;
} }
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode); for (XmlNode &currentNode : node.children()) {
XmlNode currentNode;
while (xmlIt.getNext(currentNode)) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "surface") { if (currentName == "surface") {
// image ID given inside <init_from> tags // image ID given inside <init_from> tags
@ -1289,22 +1287,24 @@ void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam)
} }
} else if (currentName == "sampler2D" && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) { } else if (currentName == "sampler2D" && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) {
// surface ID is given inside <source> tags // surface ID is given inside <source> tags
const char *content = currentNode.value(); XmlNode source = currentNode.child("source");
pParam.mType = Param_Sampler; if (source) {
pParam.mReference = content; std::string v;
XmlParser::getValueAsString(source, v);
pParam.mType = Param_Sampler;
pParam.mReference = v.c_str();
}
} else if (currentName == "sampler2D") { } else if (currentName == "sampler2D") {
// surface ID is given inside <instance_image> tags // surface ID is given inside <instance_image> tags
std::string url; XmlNode instance_image = currentNode.child("instance_image");
XmlParser::getStdStrAttribute(currentNode, "url", url); if (instance_image) {
if (url[0] != '#') { std::string url;
throw DeadlyImportError("Unsupported URL format in instance_image"); XmlParser::getStdStrAttribute(instance_image, "url", url);
} if (url[0] != '#') {
pParam.mType = Param_Sampler; throw DeadlyImportError("Unsupported URL format in instance_image");
pParam.mReference = url.c_str() + 1; }
} else if (currentName == "source") { pParam.mType = Param_Sampler;
const char *source = currentNode.child_value(); pParam.mReference = url.c_str() + 1;
if (nullptr != source) {
pParam.mReference = source;
} }
} }
} }
@ -1855,7 +1855,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
default: default:
// LineStrip is not supported due to expected index unmangling // LineStrip is not supported due to expected index unmangling
throw DeadlyImportError("Unsupported primitive type."); throw DeadlyImportError("Unsupported primitive type.");
break;
} }
// store the face size to later reconstruct the face from // store the face size to later reconstruct the face from
@ -1868,7 +1867,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
///@note This function won't work correctly if both PerIndex and PerVertex channels have same channels. ///@note This function won't work correctly if both PerIndex and PerVertex channels have same channels.
///For example if TEXCOORD present in both <vertices> and <polylist> tags this function will create wrong uv coordinates. ///For example if TEXCOORD present in both <vertices> and <polylist> tags this function will create wrong uv coordinates.
///It's not clear from COLLADA documentation is this allowed or not. For now only exporter fixed to avoid such behavior ///It's not clear from COLLADA documentation whether this is allowed or not. For now only exporter fixed to avoid such behavior
void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh &pMesh, void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh &pMesh,
std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) { std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
// calculate the base offset of the vertex whose attributes we ant to copy // calculate the base offset of the vertex whose attributes we ant to copy

View File

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

View File

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

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXUtil.h" #include "FBXUtil.h"
#include <assimp/defs.h> #include <assimp/defs.h>
#include <stdint.h> #include <stdint.h>
#include <cstdint>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/ByteSwapper.h> #include <assimp/ByteSwapper.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -139,6 +140,7 @@ size_t Offset(const char* begin, const char* cursor) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void TokenizeError(const std::string& message, const char* begin, const char* cursor) AI_WONT_RETURN_SUFFIX;
void TokenizeError(const std::string& message, const char* begin, const char* cursor) { void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
TokenizeError(message, Offset(begin, cursor)); TokenizeError(message, Offset(begin, cursor));
} }
@ -341,8 +343,7 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits) bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
{
// the first word contains the offset at which this block ends // the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@ -408,7 +409,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// XXX this is vulnerable to stack overflowing .. // XXX this is vulnerable to stack overflowing ..
while(Offset(input, cursor) < end_offset - sentinel_block_length) { while(Offset(input, cursor) < end_offset - sentinel_block_length) {
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
} }
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
@ -431,8 +432,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
{
ai_assert(input); ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file"); ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
@ -465,7 +465,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
try try
{ {
while (cursor < end ) { while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
break; break;
} }
} }

View File

@ -55,9 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/MathFunctions.h> #include <assimp/MathFunctions.h>
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/CreateAnimMesh.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/commonMetaData.h> #include <assimp/commonMetaData.h>
@ -93,6 +91,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
mSceneOut(out), mSceneOut(out),
doc(doc), doc(doc),
mRemoveEmptyBones(removeEmptyBones) { mRemoveEmptyBones(removeEmptyBones) {
// animations need to be converted first since this will // animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed // populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated. // to determine which nodes need to be generated.
@ -421,16 +421,32 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
// NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
// All transformations to the camera will be handled by its node in the scenegraph.
out_camera->mPosition = aiVector3D(0.0f); out_camera->mPosition = aiVector3D(0.0f);
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); // NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
// mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
out_camera->mClipPlaneNear = cam.NearPlane(); // TODO: This is not a complete solution for how FBX cameras can be stored.
out_camera->mClipPlaneFar = cam.FarPlane(); // TODO: Incorporate non-square pixel aspect ratio.
// TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
float fov_deg = cam.FieldOfView();
// If FOV not specified in file, compute using FilmWidth and FocalLength.
if (fov_deg == kFovUnknown) {
float film_width_inches = cam.FilmWidth();
float focal_length_mm = cam.FocalLength();
ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
} else {
// FBX fov is full-view degrees. We want half-view radians.
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
}
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
out_camera->mClipPlaneNear = cam.NearPlane(); out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane(); out_camera->mClipPlaneFar = cam.FarPlane();
} }
@ -559,16 +575,17 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool is_id[3] = { true, true, true }; bool is_id[3] = { true, true, true };
aiMatrix4x4 temp[3]; aiMatrix4x4 temp[3];
if (std::fabs(rotation.z) > angle_epsilon) { const auto rot = AI_DEG_TO_RAD(rotation);
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); if (std::fabs(rot.z) > angle_epsilon) {
aiMatrix4x4::RotationZ(rot.z, temp[2]);
is_id[2] = false; is_id[2] = false;
} }
if (std::fabs(rotation.y) > angle_epsilon) { if (std::fabs(rot.y) > angle_epsilon) {
aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); aiMatrix4x4::RotationY(rot.y, temp[1]);
is_id[1] = false; is_id[1] = false;
} }
if (std::fabs(rotation.x) > angle_epsilon) { if (std::fabs(rot.x) > angle_epsilon) {
aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); aiMatrix4x4::RotationX(rot.x, temp[0]);
is_id[0] = false; is_id[0] = false;
} }
@ -640,7 +657,7 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
const auto zero_epsilon = ai_epsilon; const auto zero_epsilon = Math::getEpsilon<ai_real>();
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -873,8 +890,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
data->Set(index++, prop.first, interpretedBool->Value()); data->Set(index++, prop.first, interpretedBool->Value());
} else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) { } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
data->Set(index++, prop.first, interpretedInt->Value()); data->Set(index++, prop.first, interpretedInt->Value());
} else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
data->Set(index++, prop.first, interpretedUInt->Value());
} else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) { } else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
data->Set(index++, prop.first, interpretedUint64->Value()); data->Set(index++, prop.first, interpretedUint64->Value());
} else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
data->Set(index++, prop.first, interpretedint64->Value());
} else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) { } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
data->Set(index++, prop.first, interpretedFloat->Value()); data->Set(index++, prop.first, interpretedFloat->Value());
} else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) { } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
@ -1176,15 +1197,23 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto &curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto &curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
//losing channel name if using shapeGeometry->Name() //losing channel name if using shapeGeometry->Name()
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name())); // if blendShapeChannel Name is empty or doesn't have a ".", add geoMetryName;
auto aniName = FixAnimMeshName(blendShapeChannel->Name());
auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
if (aniName.empty()) {
aniName = geoMetryName;
}
else if (aniName.find('.') == aniName.npos) {
aniName += "." + geoMetryName;
}
animMesh->mName.Set(aniName);
for (size_t j = 0; j < curIndices.size(); j++) { for (size_t j = 0; j < curIndices.size(); j++) {
const unsigned int curIndex = curIndices.at(j); const unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j); aiVector3D vertex = curVertices.at(j);
@ -1406,13 +1435,12 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) { for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries(); const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) { for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); const auto& curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices(); const auto& curNormals = shapeGeometry->GetNormals();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals(); const auto& curIndices = shapeGeometry->GetIndices();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
for (size_t j = 0; j < curIndices.size(); j++) { for (size_t j = 0; j < curIndices.size(); j++) {
unsigned int curIndex = curIndices.at(j); unsigned int curIndex = curIndices.at(j);
@ -1574,7 +1602,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster, void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/, std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
aiNode *) { aiNode *) {
ai_assert(cluster != nullptr); // make sure cluster valid ai_assert(cluster != nullptr); // make sure cluster valid
@ -1591,16 +1619,16 @@ void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const
bone = new aiBone(); bone = new aiBone();
bone->mName = bone_name; bone->mName = bone_name;
bone->mOffsetMatrix = cluster->Transform(); //bone->mOffsetMatrix = cluster->Transform();
// store local transform link for post processing // store local transform link for post processing
/*
bone->mOffsetMatrix = cluster->TransformLink(); bone->mOffsetMatrix = cluster->TransformLink();
bone->mOffsetMatrix.Inverse(); bone->mOffsetMatrix.Inverse();
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; const aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
*/
// //
// Now calculate the aiVertexWeights // Now calculate the aiVertexWeights
// //
@ -3196,7 +3224,6 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
aiVector3D defTranslate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f)); aiVector3D defTranslate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f));
aiVector3D defRotation = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)); aiVector3D defRotation = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f));
aiVector3D defScale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f)); aiVector3D defScale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f));
aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder);
aiVectorKey* outTranslations = new aiVectorKey[keyCount]; aiVectorKey* outTranslations = new aiVectorKey[keyCount];
aiQuatKey* outRotations = new aiQuatKey[keyCount]; aiQuatKey* outRotations = new aiQuatKey[keyCount];
@ -3212,8 +3239,9 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
} }
if (keyframeLists[TransformationComp_Rotation].size() > 0) { if (keyframeLists[TransformationComp_Rotation].size() > 0) {
InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder); InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], AI_DEG_TO_RAD(defRotation), maxTime, minTime, rotOrder);
} else { } else {
aiQuaternion defQuat = EulerToQuaternion(AI_DEG_TO_RAD(defRotation), rotOrder);
for (size_t i = 0; i < keyCount; ++i) { for (size_t i = 0; i < keyCount; ++i) {
outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps; outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
outRotations[i].mValue = defQuat; outRotations[i].mValue = defQuat;
@ -3235,7 +3263,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok); const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
if (ok && preRotation.SquareLength() > zero_epsilon) { if (ok && preRotation.SquareLength() > zero_epsilon) {
const aiQuaternion preQuat = EulerToQuaternion(preRotation, Model::RotOrder_EulerXYZ); const aiQuaternion preQuat = EulerToQuaternion(AI_DEG_TO_RAD(preRotation), Model::RotOrder_EulerXYZ);
for (size_t i = 0; i < keyCount; ++i) { for (size_t i = 0; i < keyCount; ++i) {
outRotations[i].mValue = preQuat * outRotations[i].mValue; outRotations[i].mValue = preQuat * outRotations[i].mValue;
} }
@ -3243,7 +3271,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
const aiVector3D& postRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok); const aiVector3D& postRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
if (ok && postRotation.SquareLength() > zero_epsilon) { if (ok && postRotation.SquareLength() > zero_epsilon) {
const aiQuaternion postQuat = EulerToQuaternion(postRotation, Model::RotOrder_EulerXYZ); const aiQuaternion postQuat = EulerToQuaternion(AI_DEG_TO_RAD(postRotation), Model::RotOrder_EulerXYZ);
for (size_t i = 0; i < keyCount; ++i) { for (size_t i = 0; i < keyCount; ++i) {
outRotations[i].mValue = outRotations[i].mValue * postQuat; outRotations[i].mValue = outRotations[i].mValue * postQuat;
} }

View File

@ -84,7 +84,7 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
transform = ReadMatrix(Transform); transform = ReadMatrix(Transform);
transformLink = ReadMatrix(TransformLink); transformLink = ReadMatrix(TransformLink);
// it is actually possible that there be Deformer's with no weights // it is actually possible that there are Deformer's with no weights
if (!!Indexes != !!Weights) { if (!!Indexes != !!Weights) {
DOMError("either Indexes or Weights are missing from Cluster",&element); DOMError("either Indexes or Weights are missing from Cluster",&element);
} }
@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
for (const Connection* con : conns) { for (const Connection* con : conns) {
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element); const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
if (bspc) { if (bspc) {
blendShapeChannels.push_back(bspc); auto pr = blendShapeChannels.insert(bspc);
continue; if (!pr.second) {
FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID());
}
} }
} }
} }
@ -179,8 +181,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
for (const Connection* con : conns) { for (const Connection* con : conns) {
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element); const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
if (sg) { if (sg) {
shapeGeometries.push_back(sg); auto pr = shapeGeometries.insert(sg);
continue; if (!pr.second) {
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
}
} }
} }
} }

View File

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

View File

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

View File

@ -74,8 +74,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// https://code.blender.org/2013/08/fbx-binary-file-format-specification/ // https://code.blender.org/2013/08/fbx-binary-file-format-specification/
// https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure // https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian
using namespace Assimp; using namespace Assimp;
using namespace Assimp::FBX; using namespace Assimp::FBX;
@ -1063,14 +1061,14 @@ aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
return transform; return transform;
} }
int64_t to_ktime(double ticks, const aiAnimation* anim) { inline int64_t to_ktime(double ticks, const aiAnimation* anim) {
if (anim->mTicksPerSecond <= 0) { if (anim->mTicksPerSecond <= 0) {
return static_cast<int64_t>(ticks) * FBX::SECOND; return static_cast<int64_t>(ticks) * FBX::SECOND;
} }
return (static_cast<int64_t>(ticks) / static_cast<int64_t>(anim->mTicksPerSecond)) * FBX::SECOND; return (static_cast<int64_t>(ticks / anim->mTicksPerSecond)) * FBX::SECOND;
} }
int64_t to_ktime(double time) { inline int64_t to_ktime(double time) {
return (static_cast<int64_t>(time * FBX::SECOND)); return (static_cast<int64_t>(time * FBX::SECOND));
} }
@ -1391,7 +1389,7 @@ void FBXExporter::WriteObjects ()
aiMaterial* m = mScene->mMaterials[i]; aiMaterial* m = mScene->mMaterials[i];
// these are used to receive material data // these are used to receive material data
float f; aiColor3D c; ai_real f; aiColor3D c;
// start the node record // start the node record
FBX::Node n("Material"); FBX::Node n("Material");
@ -2415,7 +2413,7 @@ void FBXExporter::WriteObjects ()
// position/translation // position/translation
for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) { for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) {
const aiVectorKey& k = na->mPositionKeys[ki]; const aiVectorKey& k = na->mPositionKeys[ki];
times.push_back(to_ktime(k.mTime)); times.push_back(to_ktime(k.mTime, anim));
xval.push_back(k.mValue.x); xval.push_back(k.mValue.x);
yval.push_back(k.mValue.y); yval.push_back(k.mValue.y);
zval.push_back(k.mValue.z); zval.push_back(k.mValue.z);
@ -2429,12 +2427,12 @@ void FBXExporter::WriteObjects ()
times.clear(); xval.clear(); yval.clear(); zval.clear(); times.clear(); xval.clear(); yval.clear(); zval.clear();
for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) { for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) {
const aiQuatKey& k = na->mRotationKeys[ki]; const aiQuatKey& k = na->mRotationKeys[ki];
times.push_back(to_ktime(k.mTime)); times.push_back(to_ktime(k.mTime, anim));
// TODO: aiQuaternion method to convert to Euler... // TODO: aiQuaternion method to convert to Euler...
aiMatrix4x4 m(k.mValue.GetMatrix()); aiMatrix4x4 m(k.mValue.GetMatrix());
aiVector3D qs, qr, qt; aiVector3D qs, qr, qt;
m.Decompose(qs, qr, qt); m.Decompose(qs, qr, qt);
qr *= DEG; qr = AI_RAD_TO_DEG(qr);
xval.push_back(qr.x); xval.push_back(qr.x);
yval.push_back(qr.y); yval.push_back(qr.y);
zval.push_back(qr.z); zval.push_back(qr.z);
@ -2447,7 +2445,7 @@ void FBXExporter::WriteObjects ()
times.clear(); xval.clear(); yval.clear(); zval.clear(); times.clear(); xval.clear(); yval.clear(); zval.clear();
for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) { for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) {
const aiVectorKey& k = na->mScalingKeys[ki]; const aiVectorKey& k = na->mScalingKeys[ki];
times.push_back(to_ktime(k.mTime)); times.push_back(to_ktime(k.mTime, anim));
xval.push_back(k.mValue.x); xval.push_back(k.mValue.x);
yval.push_back(k.mValue.y); yval.push_back(k.mValue.y);
zval.push_back(k.mValue.z); zval.push_back(k.mValue.z);
@ -2515,9 +2513,10 @@ void FBXExporter::WriteModelNode(
); );
} }
if (r != zero) { if (r != zero) {
r = AI_RAD_TO_DEG(r);
p.AddP70( p.AddP70(
"Lcl Rotation", "Lcl Rotation", "", "A", "Lcl Rotation", "Lcl Rotation", "", "A",
double(DEG*r.x), double(DEG*r.y), double(DEG*r.z) double(r.x), double(r.y), double(r.z)
); );
} }
if (s != one) { if (s != one) {
@ -2601,8 +2600,7 @@ void FBXExporter::WriteModelNodes(
transform_chain.emplace_back(elem->first, t); transform_chain.emplace_back(elem->first, t);
break; break;
case 'r': // rotation case 'r': // rotation
r *= float(DEG); transform_chain.emplace_back(elem->first, AI_RAD_TO_DEG(r));
transform_chain.emplace_back(elem->first, r);
break; break;
case 's': // scale case 's': // scale
transform_chain.emplace_back(elem->first, s); transform_chain.emplace_back(elem->first, s);

View File

@ -72,30 +72,25 @@ using namespace Assimp::Formatter;
using namespace Assimp::FBX; using namespace Assimp::FBX;
namespace { namespace {
static constexpr aiImporterDesc desc = {
static const aiImporterDesc desc = { "Autodesk FBX Importer",
"Autodesk FBX Importer", "",
"", "",
"", "",
"", aiImporterFlags_SupportTextFlavour,
aiImporterFlags_SupportTextFlavour, 0,
0, 0,
0, 0,
0, 0,
0, "fbx"
"fbx" };
};
} }
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer
FBXImporter::FBXImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const { bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head // at least ASCII-FBX files usually have a 'FBX' somewhere in their head
static const char *tokens[] = { "fbx" }; static const char *tokens[] = { " \n\r\n " };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }
@ -152,19 +147,19 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// broad-phase tokenized pass in which we identify the core // broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens; TokenList tokens;
try { Assimp::StackAllocator tempAllocator;
try {
bool is_binary = false; bool is_binary = false;
if (!strncmp(begin, "Kaydara FBX Binary", 18)) { if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
is_binary = true; is_binary = true;
TokenizeBinary(tokens, begin, contents.size()); TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
} else { } else {
Tokenize(tokens, begin); Tokenize(tokens, begin, tempAllocator);
} }
// use this information to construct a very rudimentary // use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure // parse-tree representing the FBX scope structure
Parser parser(tokens, is_binary); Parser parser(tokens, tempAllocator, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, mSettings); Document doc(parser, mSettings);
@ -183,10 +178,12 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// assimp universal format (M) // assimp universal format (M)
SetFileScale(size_relative_to_cm * 0.01f); SetFileScale(size_relative_to_cm * 0.01f);
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); // This collection does not own the memory for the tokens, but we need to call their d'tor
} catch (std::exception &) { std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
throw; } catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
throw;
} }
} }

View File

@ -70,7 +70,7 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> { class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public: public:
/// @brief The class constructor. /// @brief The class constructor.
FBXImporter(); FBXImporter() = default;
/// @brief The class destructor, default implementation. /// @brief The class destructor, default implementation.
~FBXImporter() override = default; ~FBXImporter() override = default;

View File

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

View File

@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element); const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) { if (bsp) {
blendShapes.push_back(bsp); auto pr = blendShapes.insert(bsp);
if (!pr.second) {
FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
}
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
} }
@ -464,9 +467,9 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
std::vector<int> uvIndices; std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
if (uvIndices.size() != vertex_count) { if (uvIndices.size() != mapping_offsets.size()) {
FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ", FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
uvIndices.size(), ", expected ", vertex_count); uvIndices.size(), ", expected ", mapping_offsets.size());
return; return;
} }

View File

@ -62,7 +62,7 @@ public:
/// @param name The name instance /// @param name The name instance
/// @param doc The document instance /// @param doc The document instance
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/// @brief The class destructor, default. /// @brief The class destructor, default.
virtual ~Geometry() = default; virtual ~Geometry() = default;
@ -72,11 +72,12 @@ public:
/// @brief Get the BlendShape attached to this geometry or nullptr /// @brief Get the BlendShape attached to this geometry or nullptr
/// @return The blendshape arrays. /// @return The blendshape arrays.
const std::vector<const BlendShape*>& GetBlendShapes() const; const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
private: private:
const Skin* skin; const Skin* skin;
std::vector<const BlendShape*> blendShapes; std::unordered_set<const BlendShape*> blendShapes;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;
@ -112,7 +113,7 @@ public:
/// @return The binomal vector. /// @return The binomal vector.
const std::vector<aiVector3D>& GetBinormals() const; const std::vector<aiVector3D>& GetBinormals() const;
/// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has. /// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
/// Vertices are taken from the vertex data arrays in sequential order. /// Vertices are taken from the vertex data arrays in sequential order.
/// @return The face indices vector. /// @return The face indices vector.
const std::vector<unsigned int>& GetFaceIndexCounts() const; const std::vector<unsigned int>& GetFaceIndexCounts() const;

View File

@ -45,12 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
//#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include "Common/Compression.h" #include "Common/Compression.h"
//# include <zlib.h>
//#else
//# include "../contrib/zlib/zlib.h"
//#endif
#include "FBXTokenizer.h" #include "FBXTokenizer.h"
#include "FBXParser.h" #include "FBXParser.h"
@ -88,6 +83,7 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void ParseError(const std::string& message, TokenPtr token) AI_WONT_RETURN_SUFFIX;
void ParseError(const std::string& message, TokenPtr token) void ParseError(const std::string& message, TokenPtr token)
{ {
if(token) { if(token) {
@ -115,8 +111,11 @@ namespace Assimp {
namespace FBX { namespace FBX {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { Element::Element(const Token& key_token, Parser& parser) :
key_token(key_token), compound(nullptr)
{
TokenPtr n = nullptr; TokenPtr n = nullptr;
StackAllocator &allocator = parser.GetAllocator();
do { do {
n = parser.AdvanceToNextToken(); n = parser.AdvanceToNextToken();
if(!n) { if(!n) {
@ -145,7 +144,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
} }
if (n->Type() == TokenType_OPEN_BRACKET) { if (n->Type() == TokenType_OPEN_BRACKET) {
compound.reset(new Scope(parser)); compound = new_Scope(parser);
// current token should be a TOK_CLOSE_BRACKET // current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken(); n = parser.CurrentToken();
@ -163,6 +162,15 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Element::~Element()
{
if (compound) {
delete_Scope(compound);
}
// no need to delete tokens, they are owned by the parser
}
Scope::Scope(Parser& parser,bool topLevel) Scope::Scope(Parser& parser,bool topLevel)
{ {
if(!topLevel) { if(!topLevel) {
@ -172,6 +180,7 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
} }
StackAllocator &allocator = parser.GetAllocator();
TokenPtr n = parser.AdvanceToNextToken(); TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) { if (n == nullptr) {
ParseError("unexpected end of file"); ParseError("unexpected end of file");
@ -188,36 +197,45 @@ Scope::Scope(Parser& parser,bool topLevel)
ParseError("unexpected content: empty string."); ParseError("unexpected content: empty string.");
} }
elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); auto *element = new_Element(*n, parser);
// Element() should stop at the next Key token (or right after a Close token) // Element() should stop at the next Key token (or right after a Close token)
n = parser.CurrentToken(); n = parser.CurrentToken();
if (n == nullptr) { if (n == nullptr) {
if (topLevel) { if (topLevel) {
elements.insert(ElementMap::value_type(str, element));
return; return;
} }
delete_Element(element);
ParseError("unexpected end of file",parser.LastToken()); ParseError("unexpected end of file",parser.LastToken());
} else {
elements.insert(ElementMap::value_type(str, element));
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::~Scope() { Scope::~Scope()
for(ElementMap::value_type& v : elements) { {
delete v.second; // This collection does not own the memory for the elements, but we need to call their d'tor:
for (ElementMap::value_type &v : elements) {
delete_Element(v.second);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Parser::Parser (const TokenList& tokens, bool is_binary) Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
: tokens(tokens) tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
, last()
, current()
, cursor(tokens.begin())
, is_binary(is_binary)
{ {
ASSIMP_LOG_DEBUG("Parsing FBX tokens"); ASSIMP_LOG_DEBUG("Parsing FBX tokens");
root.reset(new Scope(*this,true)); root = new_Scope(*this, true);
}
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
delete_Scope(root);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

@ -155,7 +155,7 @@ size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOut
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
size_t dst_offset = 0; size_t dst_offset = 0;
int val = 0, valb = -8; int val = 0, valb = -8;
for (size_t src_offset = 0; src_offset < realLength; ++src_offset) for (size_t src_offset = 0; src_offset < realLength && dst_offset < maxOutLength; ++src_offset)
{ {
const uint8_t table_value = Util::DecodeBase64(in[src_offset]); const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
if (table_value == 255) if (table_value == 255)

View File

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

View File

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

View File

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

View File

@ -38,9 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCBoolean.cpp /// @file IFCBoolean.cpp
* @brief Implements a subset of Ifc boolean operations /// @brief Implements a subset of Ifc boolean operations
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
@ -48,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
#include <iterator> #include <iterator>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
@ -67,8 +65,9 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this // if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this
// point leaves the plane through the other side // point leaves the plane through the other side
if (std::abs(dotOne + dotTwo) < ai_epsilon) if (std::abs(dotOne + dotTwo) < ai_epsilon) {
return false; return false;
}
// if segment starts on the plane, report a hit only if the end lies on the *other* side // if segment starts on the plane, report a hit only if the end lies on the *other* side
if (std::abs(dotTwo) < ai_epsilon) { if (std::abs(dotTwo) < ai_epsilon) {
@ -82,13 +81,15 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// ignore if segment is parallel to plane and far away from it on either side // ignore if segment is parallel to plane and far away from it on either side
// Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered // Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered
if (std::abs(dotOne) < ai_epsilon) if (std::abs(dotOne) < ai_epsilon) {
return false; return false;
}
// t must be in [0..1] if the intersection point is within the given segment // t must be in [0..1] if the intersection point is within the given segment
const IfcFloat t = dotTwo / dotOne; const IfcFloat t = dotTwo / dotOne;
if (t > 1.0 || t < 0.0) if (t > 1.0 || t < 0.0) {
return false; return false;
}
out = e0 + t * seg; out = e0 + t * seg;
return true; return true;
@ -110,11 +111,13 @@ void FilterPolygon(std::vector<IfcVector3> &resultpoly) {
FuzzyVectorCompare fz(epsilon); FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator e = std::unique(resultpoly.begin(), resultpoly.end(), fz); std::vector<IfcVector3>::iterator e = std::unique(resultpoly.begin(), resultpoly.end(), fz);
if (e != resultpoly.end()) if (e != resultpoly.end()) {
resultpoly.erase(e, resultpoly.end()); resultpoly.erase(e, resultpoly.end());
}
if (!resultpoly.empty() && fz(resultpoly.front(), resultpoly.back())) if (!resultpoly.empty() && fz(resultpoly.front(), resultpoly.back())) {
resultpoly.pop_back(); resultpoly.pop_back();
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -291,8 +294,9 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
} }
// Line segment ends at boundary -> ignore any hit, it will be handled by possibly following segments // Line segment ends at boundary -> ignore any hit, it will be handled by possibly following segments
if (endsAtSegment && !halfOpen) if (endsAtSegment && !halfOpen) {
continue; continue;
}
// Line segment starts at boundary -> generate a hit only if following that line would change the INSIDE/OUTSIDE // Line segment starts at boundary -> generate a hit only if following that line would change the INSIDE/OUTSIDE
// state. This should catch the case where a connected set of segments has a point directly on the boundary, // state. This should catch the case where a connected set of segments has a point directly on the boundary,
@ -301,15 +305,17 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
if (startsAtSegment) { if (startsAtSegment) {
IfcVector3 inside_dir = IfcVector3(b.y, -b.x, 0.0) * windingOrder; IfcVector3 inside_dir = IfcVector3(b.y, -b.x, 0.0) * windingOrder;
bool isGoingInside = (inside_dir * e) > 0.0; bool isGoingInside = (inside_dir * e) > 0.0;
if (isGoingInside == isStartAssumedInside) if (isGoingInside == isStartAssumedInside) {
continue; continue;
}
// only insert the point into the list if it is sufficiently far away from the previous intersection point. // only insert the point into the list if it is sufficiently far away from the previous intersection point.
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments. // This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if (!intersect_results.empty() && intersect_results.back().first == i - 1) { if (!intersect_results.empty() && intersect_results.back().first == i - 1) {
const IfcVector3 diff = intersect_results.back().second - e0; const IfcVector3 diff = intersect_results.back().second - e0;
if (IfcVector2(diff.x, diff.y).SquareLength() < 1e-10) if (IfcVector2(diff.x, diff.y).SquareLength() < 1e-10) {
continue; continue;
}
} }
intersect_results.emplace_back(i, e0); intersect_results.emplace_back(i, e0);
continue; continue;
@ -322,8 +328,9 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments. // This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if (!intersect_results.empty() && intersect_results.back().first == i - 1) { if (!intersect_results.empty() && intersect_results.back().first == i - 1) {
const IfcVector3 diff = intersect_results.back().second - p; const IfcVector3 diff = intersect_results.back().second - p;
if (IfcVector2(diff.x, diff.y).SquareLength() < 1e-10) if (IfcVector2(diff.x, diff.y).SquareLength() < 1e-10) {
continue; continue;
}
} }
intersect_results.emplace_back(i, p); intersect_results.emplace_back(i, p);
} }
@ -662,7 +669,8 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPoly
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedAreaSolid *as, TempMesh &result, void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedAreaSolid *as,
TempMesh &result,
const TempMesh &first_operand, const TempMesh &first_operand,
ConversionData &conv) { ConversionData &conv) {
ai_assert(as != nullptr); ai_assert(as != nullptr);
@ -763,4 +771,4 @@ void ProcessBoolean(const Schema_2x3::IfcBooleanResult &boolean, TempMesh &resul
} // namespace IFC } // namespace IFC
} // namespace Assimp } // namespace Assimp
#endif #endif // ASSIMP_BUILD_NO_IFC_IMPORTER

View File

@ -39,15 +39,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCProfile.cpp /// @file IFCProfile.cpp
* @brief Read profile and curves entities from IFC files /// @brief Read profile and curves entities from IFC files
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include "IFCUtil.h" #include "IFCUtil.h"
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
namespace { namespace {
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
@ -56,8 +56,7 @@ namespace {
class Conic : public Curve { class Conic : public Curve {
public: public:
// -------------------------------------------------- // --------------------------------------------------
Conic(const Schema_2x3::IfcConic& entity, ConversionData& conv) Conic(const Schema_2x3::IfcConic& entity, ConversionData& conv) : Curve(entity,conv) {
: Curve(entity,conv) {
IfcMatrix4 trafo; IfcMatrix4 trafo;
ConvertAxisPlacement(trafo,*entity.Position,conv); ConvertAxisPlacement(trafo,*entity.Position,conv);
@ -69,12 +68,12 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
bool IsClosed() const { bool IsClosed() const override {
return true; return true;
} }
// -------------------------------------------------- // --------------------------------------------------
size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
@ -88,7 +87,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
ParamRange GetParametricRange() const { ParamRange GetParametricRange() const override {
return std::make_pair(static_cast<IfcFloat>( 0. ), static_cast<IfcFloat>( AI_MATH_TWO_PI / conv.angle_scale )); return std::make_pair(static_cast<IfcFloat>( 0. ), static_cast<IfcFloat>( AI_MATH_TWO_PI / conv.angle_scale ));
} }
@ -102,14 +101,13 @@ protected:
class Circle : public Conic { class Circle : public Conic {
public: public:
// -------------------------------------------------- // --------------------------------------------------
Circle(const Schema_2x3::IfcCircle& entity, ConversionData& conv) Circle(const Schema_2x3::IfcCircle& entity, ConversionData& conv) : Conic(entity,conv) , entity(entity) {}
: Conic(entity,conv)
, entity(entity)
{
}
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat u) const { ~Circle() override = default;
// --------------------------------------------------
IfcVector3 Eval(IfcFloat u) const override {
u = -conv.angle_scale * u; u = -conv.angle_scale * u;
return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(std::cos(u))*p[0] + return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(std::cos(u))*p[0] +
static_cast<IfcFloat>(std::sin(u))*p[1]); static_cast<IfcFloat>(std::sin(u))*p[1]);
@ -132,7 +130,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat u) const { IfcVector3 Eval(IfcFloat u) const override {
u = -conv.angle_scale * u; u = -conv.angle_scale * u;
return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(std::cos(u))*p[0] + return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(std::cos(u))*p[0] +
static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(std::sin(u))*p[1]; static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(std::sin(u))*p[1];
@ -155,17 +153,17 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
bool IsClosed() const { bool IsClosed() const override {
return false; return false;
} }
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat u) const { IfcVector3 Eval(IfcFloat u) const override {
return p + u*v; return p + u*v;
} }
// -------------------------------------------------- // --------------------------------------------------
size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
// two points are always sufficient for a line segment // two points are always sufficient for a line segment
@ -174,7 +172,7 @@ public:
// -------------------------------------------------- // --------------------------------------------------
void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const { void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
@ -188,7 +186,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
ParamRange GetParametricRange() const { ParamRange GetParametricRange() const override {
const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity(); const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity();
return std::make_pair(-inf,+inf); return std::make_pair(-inf,+inf);
@ -234,7 +232,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat u) const { IfcVector3 Eval(IfcFloat u) const override {
if (curves.empty()) { if (curves.empty()) {
return IfcVector3(); return IfcVector3();
} }
@ -254,7 +252,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
size_t cnt = 0; size_t cnt = 0;
@ -275,7 +273,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const { void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
@ -293,7 +291,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
ParamRange GetParametricRange() const { ParamRange GetParametricRange() const override {
return std::make_pair(static_cast<IfcFloat>( 0. ),total); return std::make_pair(static_cast<IfcFloat>( 0. ),total);
} }
@ -373,27 +371,27 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat p) const { IfcVector3 Eval(IfcFloat p) const override {
ai_assert(InRange(p)); ai_assert(InRange(p));
return base->Eval( TrimParam(p) ); return base->Eval( TrimParam(p) );
} }
// -------------------------------------------------- // --------------------------------------------------
size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const override {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
return base->EstimateSampleCount(TrimParam(a),TrimParam(b)); return base->EstimateSampleCount(TrimParam(a),TrimParam(b));
} }
// -------------------------------------------------- // --------------------------------------------------
void SampleDiscrete(TempMesh& out,IfcFloat a,IfcFloat b) const { void SampleDiscrete(TempMesh& out,IfcFloat a,IfcFloat b) const override {
ai_assert(InRange(a)); ai_assert(InRange(a));
ai_assert(InRange(b)); ai_assert(InRange(b));
return base->SampleDiscrete(out,TrimParam(a),TrimParam(b)); return base->SampleDiscrete(out,TrimParam(a),TrimParam(b));
} }
// -------------------------------------------------- // --------------------------------------------------
ParamRange GetParametricRange() const { ParamRange GetParametricRange() const override {
return std::make_pair(static_cast<IfcFloat>( 0. ),maxval); return std::make_pair(static_cast<IfcFloat>( 0. ),maxval);
} }
@ -431,7 +429,7 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
IfcVector3 Eval(IfcFloat p) const { IfcVector3 Eval(IfcFloat p) const override {
ai_assert(InRange(p)); ai_assert(InRange(p));
const size_t b = static_cast<size_t>(std::floor(p)); const size_t b = static_cast<size_t>(std::floor(p));
@ -444,14 +442,14 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const override {
ai_assert(InRange(a)); ai_assert(InRange(a));
ai_assert(InRange(b)); ai_assert(InRange(b));
return static_cast<size_t>( std::ceil(b) - std::floor(a) ); return static_cast<size_t>( std::ceil(b) - std::floor(a) );
} }
// -------------------------------------------------- // --------------------------------------------------
ParamRange GetParametricRange() const { ParamRange GetParametricRange() const override {
return std::make_pair(static_cast<IfcFloat>( 0. ),static_cast<IfcFloat>(points.size()-1)); return std::make_pair(static_cast<IfcFloat>( 0. ),static_cast<IfcFloat>(points.size()-1));
} }
@ -516,7 +514,7 @@ size_t Curve::EstimateSampleCount(IfcFloat a, IfcFloat b) const {
ai_assert( InRange( a ) ); ai_assert( InRange( a ) );
ai_assert( InRange( b ) ); ai_assert( InRange( b ) );
// arbitrary default value, deriving classes should supply better suited values // arbitrary default value, deriving classes should supply better-suited values
return 16; return 16;
} }

View File

@ -38,24 +38,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCGeometry.cpp /// @file IFCGeometry.cpp
* @brief Geometry conversion and synthesis for IFC /// @brief Geometry conversion and synthesis for IFC
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include "IFCUtil.h" #include "IFCUtil.h"
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
#include "contrib/poly2tri/poly2tri/poly2tri.h"
#ifdef ASSIMP_USE_HUNTER #include "contrib/clipper/clipper.hpp"
# include <poly2tri/poly2tri.h>
# include <polyclipping/clipper.hpp>
#else
# include "../contrib/poly2tri/poly2tri/poly2tri.h"
# include "../contrib/clipper/clipper.hpp"
#endif
#include <iterator> #include <iterator>
#include <memory> #include <memory>
@ -65,8 +56,7 @@ namespace Assimp {
namespace IFC { namespace IFC {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessPolyloop(const Schema_2x3::IfcPolyLoop& loop, TempMesh& meshout, ConversionData& /*conv*/) bool ProcessPolyloop(const Schema_2x3::IfcPolyLoop& loop, TempMesh& meshout, ConversionData& /*conv*/) {
{
size_t cnt = 0; size_t cnt = 0;
for(const Schema_2x3::IfcCartesianPoint& c : loop.Polygon) { for(const Schema_2x3::IfcCartesianPoint& c : loop.Polygon) {
IfcVector3 tmp; IfcVector3 tmp;
@ -91,8 +81,7 @@ bool ProcessPolyloop(const Schema_2x3::IfcPolyLoop& loop, TempMesh& meshout, Con
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t master_bounds = (size_t)-1) void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t master_bounds = (size_t)-1) {
{
// handle all trivial cases // handle all trivial cases
if(inmesh.mVertcnt.empty()) { if(inmesh.mVertcnt.empty()) {
return; return;
@ -127,8 +116,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
if (master_bounds != (size_t)-1) { if (master_bounds != (size_t)-1) {
ai_assert(master_bounds < inmesh.mVertcnt.size()); ai_assert(master_bounds < inmesh.mVertcnt.size());
outer_polygon_it = begin + master_bounds; outer_polygon_it = begin + master_bounds;
} } else {
else {
for(iit = begin; iit != end; ++iit) { for(iit = begin; iit != end; ++iit) {
// find the polygon with the largest area and take it as the outer bound. // find the polygon with the largest area and take it as the outer bound.
IfcVector3& n = normals[std::distance(begin,iit)]; IfcVector3& n = normals[std::distance(begin,iit)];
@ -139,7 +127,8 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
} }
} }
} }
if (outer_polygon_it == end) {
if (outer_polygon_it == end) {
return; return;
} }
@ -205,40 +194,20 @@ void ProcessConnectedFaceSet(const Schema_2x3::IfcConnectedFaceSet& fset, TempMe
if(const Schema_2x3::IfcPolyLoop* const polyloop = bound.Bound->ToPtr<Schema_2x3::IfcPolyLoop>()) { if(const Schema_2x3::IfcPolyLoop* const polyloop = bound.Bound->ToPtr<Schema_2x3::IfcPolyLoop>()) {
if(ProcessPolyloop(*polyloop, meshout,conv)) { if(ProcessPolyloop(*polyloop, meshout,conv)) {
// The outer boundary is better determined by checking which // The outer boundary is better determined by checking which
// polygon covers the largest area. // polygon covers the largest area.
//if(bound.ToPtr<IfcFaceOuterBound>()) {
// ob = cnt;
//}
//++cnt;
} }
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcFaceBound entity, type is ", bound.Bound->GetClassName()); IFCImporter::LogWarn("skipping unknown IfcFaceBound entity, type is ", bound.Bound->GetClassName());
continue; continue;
} }
// And this, even though it is sometimes TRUE and sometimes FALSE,
// does not really improve results.
/*if(!IsTrue(bound.Orientation)) {
size_t c = 0;
for(unsigned int& c : meshout.vertcnt) {
std::reverse(result.verts.begin() + cnt,result.verts.begin() + cnt + c);
cnt += c;
}
}*/
} }
ProcessPolygonBoundaries(result, meshout); ProcessPolygonBoundaries(result, meshout);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessRevolvedAreaSolid(const Schema_2x3::IfcRevolvedAreaSolid& solid, TempMesh& result, ConversionData& conv) void ProcessRevolvedAreaSolid(const Schema_2x3::IfcRevolvedAreaSolid& solid, TempMesh& result, ConversionData& conv) {
{
TempMesh meshout; TempMesh meshout;
// first read the profile description // first read the profile description
@ -265,7 +234,8 @@ void ProcessRevolvedAreaSolid(const Schema_2x3::IfcRevolvedAreaSolid& solid, Tem
return; return;
} }
const unsigned int cnt_segments = std::max(2u,static_cast<unsigned int>(conv.settings.cylindricalTessellation * std::fabs(max_angle)/AI_MATH_HALF_PI_F)); const unsigned int cnt_segments =
std::max(2u,static_cast<unsigned int>(conv.settings.cylindricalTessellation * std::fabs(max_angle)/AI_MATH_HALF_PI_F));
const IfcFloat delta = max_angle/cnt_segments; const IfcFloat delta = max_angle/cnt_segments;
has_area = has_area && std::fabs(max_angle) < AI_MATH_TWO_PI_F*0.99; has_area = has_area && std::fabs(max_angle) < AI_MATH_TWO_PI_F*0.99;
@ -324,8 +294,9 @@ void ProcessRevolvedAreaSolid(const Schema_2x3::IfcRevolvedAreaSolid& solid, Tem
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh& result, ConversionData& conv) void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid,
{ TempMesh& result,
ConversionData& conv) {
const Curve* const curve = Curve::Convert(*solid.Directrix, conv); const Curve* const curve = Curve::Convert(*solid.Directrix, conv);
if(!curve) { if(!curve) {
IFCImporter::LogError("failed to convert Directrix curve (IfcSweptDiskSolid)"); IFCImporter::LogError("failed to convert Directrix curve (IfcSweptDiskSolid)");
@ -460,8 +431,7 @@ void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh&
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut) IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut) {
{
const std::vector<IfcVector3>& out = curmesh.mVerts; const std::vector<IfcVector3>& out = curmesh.mVerts;
IfcMatrix3 m; IfcMatrix3 m;
@ -504,10 +474,6 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
IfcVector3 r = (out[idx]-any_point); IfcVector3 r = (out[idx]-any_point);
r.Normalize(); r.Normalize();
//if(d) {
// *d = -any_point * nor;
//}
// Reconstruct orthonormal basis // Reconstruct orthonormal basis
// XXX use Gram Schmidt for increased robustness // XXX use Gram Schmidt for increased robustness
IfcVector3 u = r ^ nor; IfcVector3 u = r ^ nor;
@ -531,8 +497,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
const auto closeDistance = ai_epsilon; const auto closeDistance = ai_epsilon;
bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) { bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) {
if(pt1.Coordinates.size() != pt2.Coordinates.size()) if(pt1.Coordinates.size() != pt2.Coordinates.size()) {
{
IFCImporter::LogWarn("unable to compare differently-dimensioned points"); IFCImporter::LogWarn("unable to compare differently-dimensioned points");
return false; return false;
} }
@ -540,10 +505,10 @@ bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt
auto coord2 = pt2.Coordinates.begin(); auto coord2 = pt2.Coordinates.begin();
// we're just testing each dimension separately rather than doing euclidean distance, as we're // we're just testing each dimension separately rather than doing euclidean distance, as we're
// looking for very close coordinates // looking for very close coordinates
for(; coord1 != pt1.Coordinates.end(); coord1++,coord2++) for(; coord1 != pt1.Coordinates.end(); coord1++,coord2++) {
{ if(std::fabs(*coord1 - *coord2) > closeDistance) {
if(std::fabs(*coord1 - *coord2) > closeDistance)
return false; return false;
}
} }
return true; return true;
} }
@ -553,6 +518,7 @@ bool areClose(IfcVector3 pt1,IfcVector3 pt2) {
std::fabs(pt1.y - pt2.y) < closeDistance && std::fabs(pt1.y - pt2.y) < closeDistance &&
std::fabs(pt1.z - pt2.z) < closeDistance); std::fabs(pt1.z - pt2.z) < closeDistance);
} }
// Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary. // Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary.
void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const TempMesh& curve, void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const TempMesh& curve,
const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings) const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings)
@ -590,8 +556,9 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
// reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction // reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction
IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(in.data(), in.size()); IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(in.data(), in.size());
if( profileNormal * dir < 0.0 ) if( profileNormal * dir < 0.0 ) {
std::reverse(in.begin(), in.end()); std::reverse(in.begin(), in.end());
}
std::vector<IfcVector3> nors; std::vector<IfcVector3> nors;
const bool openings = !!conv.apply_openings && conv.apply_openings->size(); const bool openings = !!conv.apply_openings && conv.apply_openings->size();
@ -678,8 +645,7 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
if(n > 0) { if(n > 0) {
for(size_t i = 0; i < in.size(); ++i) for(size_t i = 0; i < in.size(); ++i)
out.push_back(in[i] + dir); out.push_back(in[i] + dir);
} } else {
else {
for(size_t i = in.size(); i--; ) for(size_t i = in.size(); i--; )
out.push_back(in[i]); out.push_back(in[i]);
} }
@ -721,9 +687,10 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid& solid, TempMesh& result, void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid& solid,
ConversionData& conv, bool collect_openings) TempMesh& result,
{ ConversionData& conv,
bool collect_openings) {
TempMesh meshout; TempMesh meshout;
// First read the profile description. // First read the profile description.
@ -761,24 +728,23 @@ void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid& solid, Tem
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid& swept, TempMesh& meshout, void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid& swept,
ConversionData& conv) TempMesh& meshout,
{ ConversionData& conv) {
if(const Schema_2x3::IfcExtrudedAreaSolid* const solid = swept.ToPtr<Schema_2x3::IfcExtrudedAreaSolid>()) { if(const Schema_2x3::IfcExtrudedAreaSolid* const solid = swept.ToPtr<Schema_2x3::IfcExtrudedAreaSolid>()) {
ProcessExtrudedAreaSolid(*solid,meshout,conv, !!conv.collect_openings); ProcessExtrudedAreaSolid(*solid,meshout,conv, !!conv.collect_openings);
} } else if(const Schema_2x3::IfcRevolvedAreaSolid* const rev = swept.ToPtr<Schema_2x3::IfcRevolvedAreaSolid>()) {
else if(const Schema_2x3::IfcRevolvedAreaSolid* const rev = swept.ToPtr<Schema_2x3::IfcRevolvedAreaSolid>()) {
ProcessRevolvedAreaSolid(*rev,meshout,conv); ProcessRevolvedAreaSolid(*rev,meshout,conv);
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcSweptAreaSolid entity, type is ", swept.GetClassName()); IFCImporter::LogWarn("skipping unknown IfcSweptAreaSolid entity, type is ", swept.GetClassName());
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned int matid, std::set<unsigned int>& mesh_indices, bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo,
ConversionData& conv) unsigned int matid,
{ std::set<unsigned int>& mesh_indices,
ConversionData& conv) {
bool fix_orientation = false; bool fix_orientation = false;
std::shared_ptr< TempMesh > meshtmp = std::make_shared<TempMesh>(); std::shared_ptr< TempMesh > meshtmp = std::make_shared<TempMesh>();
if(const Schema_2x3::IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<Schema_2x3::IfcShellBasedSurfaceModel>()) { if(const Schema_2x3::IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<Schema_2x3::IfcShellBasedSurfaceModel>()) {
@ -788,41 +754,32 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
const Schema_2x3::IfcConnectedFaceSet& fs = conv.db.MustGetObject(e).To<Schema_2x3::IfcConnectedFaceSet>(); const Schema_2x3::IfcConnectedFaceSet& fs = conv.db.MustGetObject(e).To<Schema_2x3::IfcConnectedFaceSet>();
ProcessConnectedFaceSet(fs, *meshtmp, conv); ProcessConnectedFaceSet(fs, *meshtmp, conv);
} } catch(std::bad_cast&) {
catch(std::bad_cast&) {
IFCImporter::LogWarn("unexpected type error, IfcShell ought to inherit from IfcConnectedFaceSet"); IFCImporter::LogWarn("unexpected type error, IfcShell ought to inherit from IfcConnectedFaceSet");
} }
} }
fix_orientation = true; fix_orientation = true;
} } else if(const Schema_2x3::IfcConnectedFaceSet* fset = geo.ToPtr<Schema_2x3::IfcConnectedFaceSet>()) {
else if(const Schema_2x3::IfcConnectedFaceSet* fset = geo.ToPtr<Schema_2x3::IfcConnectedFaceSet>()) {
ProcessConnectedFaceSet(*fset, *meshtmp, conv); ProcessConnectedFaceSet(*fset, *meshtmp, conv);
fix_orientation = true; fix_orientation = true;
} } else if(const Schema_2x3::IfcSweptAreaSolid* swept = geo.ToPtr<Schema_2x3::IfcSweptAreaSolid>()) {
else if(const Schema_2x3::IfcSweptAreaSolid* swept = geo.ToPtr<Schema_2x3::IfcSweptAreaSolid>()) {
ProcessSweptAreaSolid(*swept, *meshtmp, conv); ProcessSweptAreaSolid(*swept, *meshtmp, conv);
} } else if(const Schema_2x3::IfcSweptDiskSolid* disk = geo.ToPtr<Schema_2x3::IfcSweptDiskSolid>()) {
else if(const Schema_2x3::IfcSweptDiskSolid* disk = geo.ToPtr<Schema_2x3::IfcSweptDiskSolid>()) {
ProcessSweptDiskSolid(*disk, *meshtmp, conv); ProcessSweptDiskSolid(*disk, *meshtmp, conv);
} } else if(const Schema_2x3::IfcManifoldSolidBrep* brep = geo.ToPtr<Schema_2x3::IfcManifoldSolidBrep>()) {
else if(const Schema_2x3::IfcManifoldSolidBrep* brep = geo.ToPtr<Schema_2x3::IfcManifoldSolidBrep>()) {
ProcessConnectedFaceSet(brep->Outer, *meshtmp, conv); ProcessConnectedFaceSet(brep->Outer, *meshtmp, conv);
fix_orientation = true; fix_orientation = true;
} } else if(const Schema_2x3::IfcFaceBasedSurfaceModel* surf = geo.ToPtr<Schema_2x3::IfcFaceBasedSurfaceModel>()) {
else if(const Schema_2x3::IfcFaceBasedSurfaceModel* surf = geo.ToPtr<Schema_2x3::IfcFaceBasedSurfaceModel>()) {
for(const Schema_2x3::IfcConnectedFaceSet& fc : surf->FbsmFaces) { for(const Schema_2x3::IfcConnectedFaceSet& fc : surf->FbsmFaces) {
ProcessConnectedFaceSet(fc, *meshtmp, conv); ProcessConnectedFaceSet(fc, *meshtmp, conv);
} }
fix_orientation = true; fix_orientation = true;
} } else if(const Schema_2x3::IfcBooleanResult* boolean = geo.ToPtr<Schema_2x3::IfcBooleanResult>()) {
else if(const Schema_2x3::IfcBooleanResult* boolean = geo.ToPtr<Schema_2x3::IfcBooleanResult>()) {
ProcessBoolean(*boolean, *meshtmp, conv); ProcessBoolean(*boolean, *meshtmp, conv);
} } else if(geo.ToPtr<Schema_2x3::IfcBoundingBox>()) {
else if(geo.ToPtr<Schema_2x3::IfcBoundingBox>()) {
// silently skip over bounding boxes // silently skip over bounding boxes
return false; return false;
} } else {
else {
std::stringstream toLog; std::stringstream toLog;
toLog << "skipping unknown IfcGeometricRepresentationItem entity, type is " << geo.GetClassName() << " id is " << geo.GetID(); toLog << "skipping unknown IfcGeometricRepresentationItem entity, type is " << geo.GetClassName() << " id is " << geo.GetID();
IFCImporter::LogWarn(toLog.str().c_str()); IFCImporter::LogWarn(toLog.str().c_str());
@ -868,9 +825,7 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd, void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd, ConversionData& /*conv*/) {
ConversionData& /*conv*/)
{
if (!mesh_indices.empty()) { if (!mesh_indices.empty()) {
std::set<unsigned int>::const_iterator it = mesh_indices.cbegin(); std::set<unsigned int>::const_iterator it = mesh_indices.cbegin();
std::set<unsigned int>::const_iterator end = mesh_indices.cend(); std::set<unsigned int>::const_iterator end = mesh_indices.cend();
@ -886,9 +841,9 @@ void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item, bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item,
std::set<unsigned int>& mesh_indices, unsigned int mat_index, std::set<unsigned int>& mesh_indices,
ConversionData& conv) unsigned int mat_index,
{ ConversionData& conv) {
ConversionData::MeshCacheIndex idx(&item, mat_index); ConversionData::MeshCacheIndex idx(&item, mat_index);
ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(idx); ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(idx);
if (it != conv.cached_meshes.end()) { if (it != conv.cached_meshes.end()) {
@ -900,18 +855,18 @@ bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void PopulateMeshCache(const Schema_2x3::IfcRepresentationItem& item, void PopulateMeshCache(const Schema_2x3::IfcRepresentationItem& item,
const std::set<unsigned int>& mesh_indices, unsigned int mat_index, const std::set<unsigned int>& mesh_indices,
ConversionData& conv) unsigned int mat_index,
{ ConversionData& conv) {
ConversionData::MeshCacheIndex idx(&item, mat_index); ConversionData::MeshCacheIndex idx(&item, mat_index);
conv.cached_meshes[idx] = mesh_indices; conv.cached_meshes[idx] = mesh_indices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, unsigned int matid, bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item,
std::set<unsigned int>& mesh_indices, unsigned int matid,
ConversionData& conv) std::set<unsigned int>& mesh_indices,
{ ConversionData& conv) {
// determine material // determine material
unsigned int localmatid = ProcessMaterials(item.GetID(), matid, conv, true); unsigned int localmatid = ProcessMaterials(item.GetID(), matid, conv, true);
@ -920,8 +875,9 @@ bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, un
if(mesh_indices.size()) { if(mesh_indices.size()) {
PopulateMeshCache(item,mesh_indices,localmatid,conv); PopulateMeshCache(item,mesh_indices,localmatid,conv);
} }
} else {
return false;
} }
else return false;
} }
return true; return true;
} }
@ -930,4 +886,4 @@ bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, un
} // ! IFC } // ! IFC
} // ! Assimp } // ! Assimp
#endif #endif // ASSIMP_BUILD_NO_IFC_IMPORTER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCLoad.cpp /// @file IFCLoad.cpp
* @brief Implementation of the Industry Foundation Classes loader. /// @brief Implementation of the Industry Foundation Classes loader.
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
@ -92,7 +90,6 @@ using namespace Assimp::IFC;
IfcUnitAssignment IfcUnitAssignment
IfcClosedShell IfcClosedShell
IfcDoor IfcDoor
*/ */
namespace { namespace {
@ -106,7 +103,7 @@ void ConvertUnit(const ::Assimp::STEP::EXPRESS::DataType &dt, ConversionData &co
} // namespace } // namespace
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Industry Foundation Classes (IFC) Importer", "Industry Foundation Classes (IFC) Importer",
"", "",
"", "",
@ -119,14 +116,6 @@ static const aiImporterDesc desc = {
"ifc ifczip step stp" "ifc ifczip step stp"
}; };
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
IFCImporter::IFCImporter() = default;
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
IFCImporter::~IFCImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -196,7 +185,7 @@ void IFCImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
size_t total = 0; size_t total = 0;
int read = 0; int read = 0;
do { do {
int bufferSize = fileInfo.uncompressed_size < INT16_MAX ? fileInfo.uncompressed_size : INT16_MAX; unsigned bufferSize = fileInfo.uncompressed_size < INT16_MAX ? static_cast<unsigned>(fileInfo.uncompressed_size) : INT16_MAX;
void *buffer = malloc(bufferSize); void *buffer = malloc(bufferSize);
read = unzReadCurrentFile(zip, buffer, bufferSize); read = unzReadCurrentFile(zip, buffer, bufferSize);
if (read > 0) { if (read > 0) {
@ -256,7 +245,12 @@ void IFCImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// tell the reader for which types we need to simulate STEPs reverse indices // tell the reader for which types we need to simulate STEPs reverse indices
static const char *const inverse_indices_to_track[] = { static const char *const inverse_indices_to_track[] = {
"ifcrelcontainedinspatialstructure", "ifcrelaggregates", "ifcrelvoidselement", "ifcreldefinesbyproperties", "ifcpropertyset", "ifcstyleditem" "ifcrelcontainedinspatialstructure",
"ifcrelaggregates",
"ifcrelvoidselement",
"ifcreldefinesbyproperties",
"ifcpropertyset",
"ifcstyleditem"
}; };
// feed the IFC schema into the reader and pre-parse all lines // feed the IFC schema into the reader and pre-parse all lines
@ -928,4 +922,4 @@ void MakeTreeRelative(ConversionData &conv) {
} // namespace } // namespace
#endif #endif // ASSIMP_BUILD_NO_IFC_IMPORTER

View File

@ -87,8 +87,8 @@ public:
int cylindricalTessellation; int cylindricalTessellation;
}; };
IFCImporter(); IFCImporter() = default;
~IFCImporter() override; ~IFCImporter() override = default;
// -------------------- // --------------------
bool CanRead(const std::string &pFile, bool CanRead(const std::string &pFile,

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCMaterial.cpp /// @file IFCMaterial.cpp
* @brief Implementation of conversion routines to convert IFC materials to aiMaterial /// @brief Implementation of conversion routines to convert IFC materials to aiMaterial
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
@ -174,7 +172,6 @@ unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionDat
aiString name; aiString name;
name.Set("<IFCDefault>"); name.Set("<IFCDefault>");
// ConvertColorToString( color, name);
// look if there's already a default material with this base color // look if there's already a default material with this base color
for( size_t a = 0; a < conv.materials.size(); ++a ) { for( size_t a = 0; a < conv.materials.size(); ++a ) {

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCProfile.cpp /// @file IFCProfile.cpp
* @brief Read profile and curves entities from IFC files /// @brief Read profile and curves entities from IFC files
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
@ -52,8 +50,9 @@ namespace Assimp {
namespace IFC { namespace IFC {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessPolyLine(const Schema_2x3::IfcPolyline& def, TempMesh& meshout, ConversionData& /*conv*/) void ProcessPolyLine(const Schema_2x3::IfcPolyline& def,
{ TempMesh& meshout,
ConversionData& /*conv*/) {
// this won't produce a valid mesh, it just spits out a list of vertices // this won't produce a valid mesh, it just spits out a list of vertices
IfcVector3 t; IfcVector3 t;
for(const Schema_2x3::IfcCartesianPoint& cp : def.Points) { for(const Schema_2x3::IfcCartesianPoint& cp : def.Points) {
@ -64,8 +63,9 @@ void ProcessPolyLine(const Schema_2x3::IfcPolyline& def, TempMesh& meshout, Conv
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, ConversionData& conv) bool ProcessCurve(const Schema_2x3::IfcCurve& curve,
{ TempMesh& meshout,
ConversionData& conv) {
std::unique_ptr<const Curve> cv(Curve::Convert(curve,conv)); std::unique_ptr<const Curve> cv(Curve::Convert(curve,conv));
if (!cv) { if (!cv) {
IFCImporter::LogWarn("skipping unknown IfcCurve entity, type is ", curve.GetClassName()); IFCImporter::LogWarn("skipping unknown IfcCurve entity, type is ", curve.GetClassName());
@ -90,20 +90,23 @@ bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, Convers
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessClosedProfile(const Schema_2x3::IfcArbitraryClosedProfileDef& def, TempMesh& meshout, ConversionData& conv) void ProcessClosedProfile(const Schema_2x3::IfcArbitraryClosedProfileDef& def,
{ TempMesh& meshout,
ConversionData& conv) {
ProcessCurve(def.OuterCurve,meshout,conv); ProcessCurve(def.OuterCurve,meshout,conv);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessOpenProfile(const Schema_2x3::IfcArbitraryOpenProfileDef& def, TempMesh& meshout, ConversionData& conv) void ProcessOpenProfile(const Schema_2x3::IfcArbitraryOpenProfileDef& def,
{ TempMesh& meshout,
ConversionData& conv) {
ProcessCurve(def.Curve,meshout,conv); ProcessCurve(def.Curve,meshout,conv);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& conv) void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& def,
{ TempMesh& meshout,
ConversionData& conv) {
if(const Schema_2x3::IfcRectangleProfileDef* const cprofile = def.ToPtr<Schema_2x3::IfcRectangleProfileDef>()) { if(const Schema_2x3::IfcRectangleProfileDef* const cprofile = def.ToPtr<Schema_2x3::IfcRectangleProfileDef>()) {
const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f; const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f;
@ -113,8 +116,7 @@ void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& de
meshout.mVerts.emplace_back(-x,-y, 0.f ); meshout.mVerts.emplace_back(-x,-y, 0.f );
meshout.mVerts.emplace_back( x,-y, 0.f ); meshout.mVerts.emplace_back( x,-y, 0.f );
meshout.mVertcnt.push_back(4); meshout.mVertcnt.push_back(4);
} } else if( const Schema_2x3::IfcCircleProfileDef* const circle = def.ToPtr<Schema_2x3::IfcCircleProfileDef>()) {
else if( const Schema_2x3::IfcCircleProfileDef* const circle = def.ToPtr<Schema_2x3::IfcCircleProfileDef>()) {
if(def.ToPtr<Schema_2x3::IfcCircleHollowProfileDef>()) { if(def.ToPtr<Schema_2x3::IfcCircleHollowProfileDef>()) {
// TODO // TODO
} }
@ -129,8 +131,7 @@ void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& de
} }
meshout.mVertcnt.push_back(static_cast<unsigned int>(segments)); meshout.mVertcnt.push_back(static_cast<unsigned int>(segments));
} } else if( const Schema_2x3::IfcIShapeProfileDef* const ishape = def.ToPtr<Schema_2x3::IfcIShapeProfileDef>()) {
else if( const Schema_2x3::IfcIShapeProfileDef* const ishape = def.ToPtr<Schema_2x3::IfcIShapeProfileDef>()) {
// construct simplified IBeam shape // construct simplified IBeam shape
const IfcFloat offset = (ishape->OverallWidth - ishape->WebThickness) / 2; const IfcFloat offset = (ishape->OverallWidth - ishape->WebThickness) / 2;
const IfcFloat inner_height = ishape->OverallDepth - ishape->FlangeThickness * 2; const IfcFloat inner_height = ishape->OverallDepth - ishape->FlangeThickness * 2;
@ -150,8 +151,7 @@ void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& de
meshout.mVerts.emplace_back(ishape->OverallWidth,0,0); meshout.mVerts.emplace_back(ishape->OverallWidth,0,0);
meshout.mVertcnt.push_back(12); meshout.mVertcnt.push_back(12);
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcParameterizedProfileDef entity, type is ", def.GetClassName()); IFCImporter::LogWarn("skipping unknown IfcParameterizedProfileDef entity, type is ", def.GetClassName());
return; return;
} }
@ -162,18 +162,14 @@ void ProcessParametrizedProfile(const Schema_2x3::IfcParameterizedProfileDef& de
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessProfile(const Schema_2x3::IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv) bool ProcessProfile(const Schema_2x3::IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv) {
{
if(const Schema_2x3::IfcArbitraryClosedProfileDef* const cprofile = prof.ToPtr<Schema_2x3::IfcArbitraryClosedProfileDef>()) { if(const Schema_2x3::IfcArbitraryClosedProfileDef* const cprofile = prof.ToPtr<Schema_2x3::IfcArbitraryClosedProfileDef>()) {
ProcessClosedProfile(*cprofile,meshout,conv); ProcessClosedProfile(*cprofile,meshout,conv);
} } else if(const Schema_2x3::IfcArbitraryOpenProfileDef* const copen = prof.ToPtr<Schema_2x3::IfcArbitraryOpenProfileDef>()) {
else if(const Schema_2x3::IfcArbitraryOpenProfileDef* const copen = prof.ToPtr<Schema_2x3::IfcArbitraryOpenProfileDef>()) {
ProcessOpenProfile(*copen,meshout,conv); ProcessOpenProfile(*copen,meshout,conv);
} } else if(const Schema_2x3::IfcParameterizedProfileDef* const cparam = prof.ToPtr<Schema_2x3::IfcParameterizedProfileDef>()) {
else if(const Schema_2x3::IfcParameterizedProfileDef* const cparam = prof.ToPtr<Schema_2x3::IfcParameterizedProfileDef>()) {
ProcessParametrizedProfile(*cparam,meshout,conv); ProcessParametrizedProfile(*cparam,meshout,conv);
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcProfileDef entity, type is ", prof.GetClassName()); IFCImporter::LogWarn("skipping unknown IfcProfileDef entity, type is ", prof.GetClassName());
return false; return false;
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,14 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file IFCUtil.cpp /// @file IFCUtil.cpp
* @brief Implementation of conversion routines for some common Ifc helper entities. /// @brief Implementation of conversion routines for some common Ifc helper entities.
*/
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include "AssetLib/IFC/IFCUtil.h" #include "AssetLib/IFC/IFCUtil.h"
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "Geometry/GeometryUtils.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
namespace Assimp { namespace Assimp {
@ -65,8 +64,7 @@ void TempOpening::Transform(const IfcMatrix4& mat) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiMesh* TempMesh::ToMesh() aiMesh* TempMesh::ToMesh() {
{
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0))); ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0)));
if (mVerts.empty()) { if (mVerts.empty()) {
@ -104,36 +102,31 @@ aiMesh* TempMesh::ToMesh()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Clear() void TempMesh::Clear() {
{
mVerts.clear(); mVerts.clear();
mVertcnt.clear(); mVertcnt.clear();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Transform(const IfcMatrix4& mat) void TempMesh::Transform(const IfcMatrix4& mat) {
{
for(IfcVector3& v : mVerts) { for(IfcVector3& v : mVerts) {
v *= mat; v *= mat;
} }
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
IfcVector3 TempMesh::Center() const IfcVector3 TempMesh::Center() const {
{ return mVerts.empty() ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(),mVerts.end(),IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(),mVerts.end(),IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Append(const TempMesh& other) void TempMesh::Append(const TempMesh& other) {
{
mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end()); mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end());
mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end()); mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end());
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::RemoveDegenerates() void TempMesh::RemoveDegenerates() {
{
// The strategy is simple: walk the mesh and compute normals using // The strategy is simple: walk the mesh and compute normals using
// Newell's algorithm. The length of the normals gives the area // Newell's algorithm. The length of the normals gives the area
// of the polygons, which is close to zero for lines. // of the polygons, which is close to zero for lines.
@ -166,11 +159,9 @@ void TempMesh::RemoveDegenerates()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize) IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize) {
{
std::vector<IfcFloat> temp((cnt+2)*3); std::vector<IfcFloat> temp((cnt+2)*3);
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs ) for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs ) {
{
const IfcVector3& v = vtcs[vofs]; const IfcVector3& v = vtcs[vofs];
temp[i++] = v.x; temp[i++] = v.x;
temp[i++] = v.y; temp[i++] = v.y;
@ -184,9 +175,8 @@ IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bo
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals, void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
bool normalize, bool normalize,
size_t ofs) const size_t ofs) const {
{
size_t max_vcount = 0; size_t max_vcount = 0;
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit; std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit;
for(iit = begin; iit != end; ++iit) { for(iit = begin; iit != end; ++iit) {
@ -235,7 +225,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
struct CompareVector { struct CompareVector {
bool operator () (const IfcVector3& a, const IfcVector3& b) const { bool operator () (const IfcVector3& a, const IfcVector3& b) const {
IfcVector3 d = a - b; IfcVector3 d = a - b;
IfcFloat eps = ai_epsilon; constexpr IfcFloat eps = ai_epsilon;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps); return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
} }
}; };
@ -249,29 +239,27 @@ struct FindVector {
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::FixupFaceOrientation() void TempMesh::FixupFaceOrientation() {
{
const IfcVector3 vavg = Center(); const IfcVector3 vavg = Center();
// create a list of start indices for all faces to allow random access to faces // create a list of start indices for all faces to allow random access to faces
std::vector<size_t> faceStartIndices(mVertcnt.size()); std::vector<size_t> faceStartIndices(mVertcnt.size());
for( size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a ) for( size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a ) {
faceStartIndices[a] = i; faceStartIndices[a] = i;
}
// list all faces on a vertex // list all faces on a vertex
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex; std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
for( size_t a = 0; a < mVertcnt.size(); ++a ) for( size_t a = 0; a < mVertcnt.size(); ++a ) {
{ for( size_t b = 0; b < mVertcnt[a]; ++b ) {
for( size_t b = 0; b < mVertcnt[a]; ++b )
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a); facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
}
} }
// determine neighbourhood for all polys // determine neighbourhood for all polys
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX); std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
std::vector<size_t> tempIntersect(10); std::vector<size_t> tempIntersect(10);
for( size_t a = 0; a < mVertcnt.size(); ++a ) for( size_t a = 0; a < mVertcnt.size(); ++a ) {
{ for( size_t b = 0; b < mVertcnt[a]; ++b ) {
for( size_t b = 0; b < mVertcnt[a]; ++b )
{
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a]; size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
const std::vector<size_t>& facesOnB = facesByVertex[mVerts[ib]]; const std::vector<size_t>& facesOnB = facesByVertex[mVerts[ib]];
const std::vector<size_t>& facesOnNB = facesByVertex[mVerts[nib]]; const std::vector<size_t>& facesOnNB = facesByVertex[mVerts[nib]];
@ -280,10 +268,12 @@ void TempMesh::FixupFaceOrientation()
std::vector<size_t>::iterator sectend = std::set_intersection( std::vector<size_t>::iterator sectend = std::set_intersection(
facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart); facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart);
if( std::distance(sectstart, sectend) != 2 ) if( std::distance(sectstart, sectend) != 2 ) {
continue; continue;
if( *sectstart == a ) }
if( *sectstart == a ) {
++sectstart; ++sectstart;
}
neighbour[ib] = *sectstart; neighbour[ib] = *sectstart;
} }
} }
@ -292,15 +282,14 @@ void TempMesh::FixupFaceOrientation()
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring // facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
// faces to have the same winding until all faces have been tested. // faces to have the same winding until all faces have been tested.
std::vector<bool> faceDone(mVertcnt.size(), false); std::vector<bool> faceDone(mVertcnt.size(), false);
while( std::count(faceDone.begin(), faceDone.end(), false) != 0 ) while( std::count(faceDone.begin(), faceDone.end(), false) != 0 ) {
{
// find the farthest of the remaining faces // find the farthest of the remaining faces
size_t farthestIndex = SIZE_MAX; size_t farthestIndex = SIZE_MAX;
IfcFloat farthestDistance = -1.0; IfcFloat farthestDistance = -1.0;
for( size_t a = 0; a < mVertcnt.size(); ++a ) for( size_t a = 0; a < mVertcnt.size(); ++a ) {
{ if( faceDone[a] ) {
if( faceDone[a] )
continue; continue;
}
IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a], IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]); mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]);
IfcFloat dst = (faceCenter - vavg).SquareLength(); IfcFloat dst = (faceCenter - vavg).SquareLength();
@ -314,8 +303,7 @@ void TempMesh::FixupFaceOrientation()
/ IfcFloat(mVertcnt[farthestIndex]); / IfcFloat(mVertcnt[farthestIndex]);
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in // We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
// the file. // the file.
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 ) if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 ) {
{
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex]; size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc); std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc); std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
@ -332,19 +320,18 @@ void TempMesh::FixupFaceOrientation()
todo.push_back(farthestIndex); todo.push_back(farthestIndex);
// go over its neighbour faces recursively and adapt their winding order to match the farthest face // go over its neighbour faces recursively and adapt their winding order to match the farthest face
while( !todo.empty() ) while( !todo.empty() ) {
{
size_t tdf = todo.back(); size_t tdf = todo.back();
size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf]; size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
todo.pop_back(); todo.pop_back();
// check its neighbours // check its neighbours
for( size_t a = 0; a < vc; ++a ) for( size_t a = 0; a < vc; ++a ) {
{
// ignore neighbours if we already checked them // ignore neighbours if we already checked them
size_t nbi = neighbour[vsi + a]; size_t nbi = neighbour[vsi + a];
if( nbi == SIZE_MAX || faceDone[nbi] ) if( nbi == SIZE_MAX || faceDone[nbi] ) {
continue; continue;
}
const IfcVector3& vp = mVerts[vsi + a]; const IfcVector3& vp = mVerts[vsi + a];
size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi]; size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi];
@ -387,32 +374,8 @@ void TempMesh::RemoveAdjacentDuplicates() {
IfcVector3 vmin,vmax; IfcVector3 vmin,vmax;
ArrayBounds(&*base, cnt ,vmin,vmax); ArrayBounds(&*base, cnt ,vmin,vmax);
const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9); const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9);
//const IfcFloat dotepsilon = 1e-9;
//// look for vertices that lie directly on the line between their predecessor and their
//// successor and replace them with either of them.
//for(size_t i = 0; i < cnt; ++i) {
// IfcVector3& v1 = *(base+i), &v0 = *(base+(i?i-1:cnt-1)), &v2 = *(base+(i+1)%cnt);
// const IfcVector3& d0 = (v1-v0), &d1 = (v2-v1);
// const IfcFloat l0 = d0.SquareLength(), l1 = d1.SquareLength();
// if (!l0 || !l1) {
// continue;
// }
// const IfcFloat d = (d0/std::sqrt(l0))*(d1/std::sqrt(l1));
// if ( d >= 1.f-dotepsilon ) {
// v1 = v0;
// }
// else if ( d < -1.f+dotepsilon ) {
// v2 = v1;
// continue;
// }
//}
// drop any identical, adjacent vertices. this pass will collect the dropouts // drop any identical, adjacent vertices. this pass will collect the dropouts
// of the previous pass as a side-effect. // of the previous pass as a side-effect.
FuzzyVectorCompare fz(epsilon); FuzzyVectorCompare fz(epsilon);
@ -439,78 +402,58 @@ void TempMesh::RemoveAdjacentDuplicates() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Swap(TempMesh& other) void TempMesh::Swap(TempMesh& other) {
{
mVertcnt.swap(other.mVertcnt); mVertcnt.swap(other.mVertcnt);
mVerts.swap(other.mVerts); mVerts.swap(other.mVerts);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in) bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in) {
{
return (std::string)in == "TRUE" || (std::string)in == "T"; return (std::string)in == "TRUE" || (std::string)in == "T";
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcFloat ConvertSIPrefix(const std::string& prefix) IfcFloat ConvertSIPrefix(const std::string& prefix) {
{
if (prefix == "EXA") { if (prefix == "EXA") {
return 1e18f; return 1e18f;
} } else if (prefix == "PETA") {
else if (prefix == "PETA") {
return 1e15f; return 1e15f;
} } else if (prefix == "TERA") {
else if (prefix == "TERA") {
return 1e12f; return 1e12f;
} } else if (prefix == "GIGA") {
else if (prefix == "GIGA") {
return 1e9f; return 1e9f;
} } else if (prefix == "MEGA") {
else if (prefix == "MEGA") {
return 1e6f; return 1e6f;
} } else if (prefix == "KILO") {
else if (prefix == "KILO") {
return 1e3f; return 1e3f;
} } else if (prefix == "HECTO") {
else if (prefix == "HECTO") {
return 1e2f; return 1e2f;
} } else if (prefix == "DECA") {
else if (prefix == "DECA") {
return 1e-0f; return 1e-0f;
} } else if (prefix == "DECI") {
else if (prefix == "DECI") {
return 1e-1f; return 1e-1f;
} } else if (prefix == "CENTI") {
else if (prefix == "CENTI") {
return 1e-2f; return 1e-2f;
} } else if (prefix == "MILLI") {
else if (prefix == "MILLI") {
return 1e-3f; return 1e-3f;
} } else if (prefix == "MICRO") {
else if (prefix == "MICRO") {
return 1e-6f; return 1e-6f;
} } else if (prefix == "NANO") {
else if (prefix == "NANO") {
return 1e-9f; return 1e-9f;
} } else if (prefix == "PICO") {
else if (prefix == "PICO") {
return 1e-12f; return 1e-12f;
} } else if (prefix == "FEMTO") {
else if (prefix == "FEMTO") {
return 1e-15f; return 1e-15f;
} } else if (prefix == "ATTO") {
else if (prefix == "ATTO") {
return 1e-18f; return 1e-18f;
} } else {
else {
IFCImporter::LogError("Unrecognized SI prefix: ", prefix); IFCImporter::LogError("Unrecognized SI prefix: ", prefix);
return 1; return 1;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in) void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in) {
{
out.r = static_cast<float>( in.Red ); out.r = static_cast<float>( in.Red );
out.g = static_cast<float>( in.Green ); out.g = static_cast<float>( in.Green );
out.b = static_cast<float>( in.Blue ); out.b = static_cast<float>( in.Blue );
@ -518,8 +461,10 @@ void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base) void ConvertColor(aiColor4D& out,
{ const Schema_2x3::IfcColourOrFactor& in,
ConversionData& conv,
const aiColor4D* base) {
if (const ::Assimp::STEP::EXPRESS::REAL* const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) { if (const ::Assimp::STEP::EXPRESS::REAL* const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
out.r = out.g = out.b = static_cast<float>(*r); out.r = out.g = out.b = static_cast<float>(*r);
if(base) { if(base) {
@ -527,20 +472,18 @@ void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,Conver
out.g *= static_cast<float>( base->g ); out.g *= static_cast<float>( base->g );
out.b *= static_cast<float>( base->b ); out.b *= static_cast<float>( base->b );
out.a = static_cast<float>( base->a ); out.a = static_cast<float>( base->a );
} else {
out.a = 1.0;
} }
else out.a = 1.0; } else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
}
else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
ConvertColor(out,*rgb); ConvertColor(out,*rgb);
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity"); IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in) void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in) {
{
out = IfcVector3(); out = IfcVector3();
for(size_t i = 0; i < in.Coordinates.size(); ++i) { for(size_t i = 0; i < in.Coordinates.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.Coordinates[i]; out[static_cast<unsigned int>(i)] = in.Coordinates[i];
@ -548,15 +491,13 @@ void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint&
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in) void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in) {
{
ConvertDirection(out,in.Orientation); ConvertDirection(out,in.Orientation);
out *= in.Magnitude; out *= in.Magnitude;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in) void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in) {
{
out = IfcVector3(); out = IfcVector3();
for(size_t i = 0; i < in.DirectionRatios.size(); ++i) { for(size_t i = 0; i < in.DirectionRatios.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i]; out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
@ -570,8 +511,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z) void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z) {
{
out.a1 = x.x; out.a1 = x.x;
out.b1 = x.y; out.b1 = x.y;
out.c1 = x.z; out.c1 = x.z;
@ -586,8 +526,7 @@ void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in) void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location); ConvertCartesianPoint(loc,in.Location);
@ -611,8 +550,7 @@ void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in) void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location); ConvertCartesianPoint(loc,in.Location);
@ -628,34 +566,28 @@ void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in) void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in) {
{
ConvertCartesianPoint(pos,in.Location); ConvertCartesianPoint(pos,in.Location);
if (in.Axis) { if (in.Axis) {
ConvertDirection(axis,in.Axis.Get()); ConvertDirection(axis,in.Axis.Get());
} } else {
else {
axis = IfcVector3(0.f,0.f,1.f); axis = IfcVector3(0.f,0.f,1.f);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv) void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv) {
{
if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) { if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
ConvertAxisPlacement(out,*pl3); ConvertAxisPlacement(out,*pl3);
} } else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
ConvertAxisPlacement(out,*pl2); ConvertAxisPlacement(out,*pl2);
} } else {
else {
IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity"); IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op) void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,op.LocalOrigin); ConvertCartesianPoint(loc,op.LocalOrigin);
@ -676,14 +608,12 @@ void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTra
IfcMatrix4::Translation(loc,locm); IfcMatrix4::Translation(loc,locm);
AssignMatrixAxes(out,x,y,z); AssignMatrixAxes(out,x,y,z);
IfcVector3 vscale; IfcVector3 vscale;
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) { if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
vscale.x = nuni->Scale?op.Scale.Get():1.f; vscale.x = nuni->Scale?op.Scale.Get():1.f;
vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f; vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f;
vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f; vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f;
} } else {
else {
const IfcFloat sc = op.Scale?op.Scale.Get():1.f; const IfcFloat sc = op.Scale?op.Scale.Get():1.f;
vscale = IfcVector3(sc,sc,sc); vscale = IfcVector3(sc,sc,sc);
} }
@ -694,8 +624,7 @@ void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTra
out = locm * out * s; out = locm * out * s;
} }
} // ! IFC } // ! IFC
} // ! Assimp } // ! Assimp
#endif #endif // ASSIMP_BUILD_NO_IFC_IMPORTER

View File

@ -59,7 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// http://sauerbraten.org/iqm/ // http://sauerbraten.org/iqm/
// https://github.com/lsalzman/iqm // https://github.com/lsalzman/iqm
inline void swap_block( uint32_t *block, size_t size ){ inline void swap_block( uint32_t *block, size_t size ){
(void)block; // suppress 'unreferenced formal parameter' MSVC warning (void)block; // suppress 'unreferenced formal parameter' MSVC warning
size >>= 2; size >>= 2;
@ -67,7 +66,7 @@ inline void swap_block( uint32_t *block, size_t size ){
AI_SWAP4( block[ i ] ); AI_SWAP4( block[ i ] );
} }
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Inter-Quake Model Importer", "Inter-Quake Model Importer",
"", "",
"", "",
@ -100,13 +99,6 @@ bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
if (!pIOHandler) { if (!pIOHandler) {
return true; return true;
} }
/*
* don't use CheckMagicToken because that checks with swapped bytes too, leading to false
* positives. This magic is not uint32_t, but char[4], so memcmp is the best way
const char* tokens[] = {"3DMO", "3dmo"};
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
*/
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
unsigned char data[15]; unsigned char data[15];
if (!pStream || 15 != pStream->Read(data, 1, 15)) { if (!pStream || 15 != pStream->Read(data, 1, 15)) {

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -56,17 +56,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Irrlicht Mesh Reader", "Irrlicht Mesh Reader",
"", "",
"", "",
"http://irrlicht.sourceforge.net/", "http://irrlicht.sourceforge.net/",
aiImporterFlags_SupportTextFlavour, aiImporterFlags_SupportTextFlavour,
0, 0,
0, 0,
0, 0,
0, 0,
"xml irrmesh" "xml irrmesh"
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -80,419 +80,443 @@ IRRMeshImporter::~IRRMeshImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
/* NOTE: A simple check for the file extension is not enough /* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic * here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and * and could be collada, too. So we need to open the file and
* search for typical tokens. * search for typical tokens.
*/ */
static const char *tokens[] = { "irrmesh" }; static const char *tokens[] = { "irrmesh" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all file extensions which are handled by this class // Get a list of all file extensions which are handled by this class
const aiImporterDesc *IRRMeshImporter::GetInfo() const { const aiImporterDesc *IRRMeshImporter::GetInfo() const {
return &desc; return &desc;
} }
static void releaseMaterial(aiMaterial **mat) { static void releaseMaterial(aiMaterial **mat) {
if (*mat != nullptr) { if (*mat != nullptr) {
delete *mat; delete *mat;
*mat = nullptr; *mat = nullptr;
} }
} }
static void releaseMesh(aiMesh **mesh) { static void releaseMesh(aiMesh **mesh) {
if (*mesh != nullptr) { if (*mesh != nullptr) {
delete *mesh; delete *mesh;
*mesh = nullptr; *mesh = nullptr;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void IRRMeshImporter::InternReadFile(const std::string &pFile, void IRRMeshImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) { aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file // Check whether we can read from the file
if (file == nullptr) if (file == nullptr)
throw DeadlyImportError("Failed to open IRRMESH file ", pFile); throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
// Construct the irrXML parser // Construct the irrXML parser
XmlParser parser; XmlParser parser;
if (!parser.parse( file.get() )) { if (!parser.parse(file.get())) {
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile); throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
} }
XmlNode root = parser.getRootNode(); XmlNode root = parser.getRootNode();
// final data // final data
std::vector<aiMaterial *> materials; std::vector<aiMaterial *> materials;
std::vector<aiMesh *> meshes; std::vector<aiMesh *> meshes;
materials.reserve(5); materials.reserve(5);
meshes.reserve(5); meshes.reserve(5);
// temporary data - current mesh buffer // temporary data - current mesh buffer
aiMaterial *curMat = nullptr; // TODO move all these to inside loop
aiMesh *curMesh = nullptr; aiMaterial *curMat = nullptr;
unsigned int curMatFlags = 0; aiMesh *curMesh = nullptr;
unsigned int curMatFlags = 0;
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents; std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
std::vector<aiColor4D> curColors; std::vector<aiColor4D> curColors;
std::vector<aiVector3D> curUVs, curUV2s; std::vector<aiVector3D> curUVs, curUV2s;
// some temporary variables // some temporary variables
int textMeaning = 0; // textMeaning is a 15 year old variable, that could've been an enum
int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents // int textMeaning = 0; // 0=none? 1=vertices 2=indices
bool useColors = false; // int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
bool useColors = false;
// Parse the XML file /*
for (pugi::xml_node child : root.children()) { ** irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
if (child.type() == pugi::node_element) { ** Each <buffer> contains <material>, <vertices>, and <indices>
if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) { ** <material> tags here directly owns the material data specs
// end of previous buffer. A material and a mesh should be there ** <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
if (!curMat || !curMesh) { ** <boundingbox> is ignored, I think assimp recalculates those?
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;
curVertices.clear(); // Parse the XML file
curColors.clear(); pugi::xml_node const &meshNode = root.child("mesh");
curNormals.clear(); for (pugi::xml_node bufferNode : meshNode.children()) {
curUV2s.clear(); if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
curUVs.clear(); // Might be a useless warning
curTangents.clear(); ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
curBitangents.clear(); continue;
} }
if (!ASSIMP_stricmp(child.name(), "material")) { curMat = nullptr;
if (curMat) { curMesh = nullptr;
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");
if (!num) { curVertices.clear();
// This is possible ... remove the mesh from the list and skip further reading curColors.clear();
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices"); curNormals.clear();
curUV2s.clear();
curUVs.clear();
curTangents.clear();
curBitangents.clear();
releaseMaterial(&curMat); // TODO ensure all three nodes are present and populated
releaseMesh(&curMesh); // before allocating everything
textMeaning = 0;
continue;
}
curVertices.reserve(num); // Get first material node
curNormals.reserve(num); pugi::xml_node materialNode = bufferNode.child("material");
curColors.reserve(num); if (materialNode) {
curUVs.reserve(num); 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 // Get first vertices node
//const char *t = reader->getAttributeValueSafe("type"); pugi::xml_node verticesNode = bufferNode.child("vertices");
pugi::xml_attribute t = child.attribute("type"); if (verticesNode) {
if (!ASSIMP_stricmp("2tcoords", t.name())) { pugi::xml_attribute vertexCountAttrib = verticesNode.attribute("vertexCount");
curUV2s.reserve(num); int vertexCount = vertexCountAttrib.as_int();
vertexFormat = 1; 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) { curVertices.reserve(vertexCount);
// ********************************************************* curNormals.reserve(vertexCount);
// We have a second texture! So use this UV channel curColors.reserve(vertexCount);
// for it. The 2nd texture can be either a normal curUVs.reserve(vertexCount);
// texture (solid_2layer or lightmap_xxx) or a normal
// map (normal_..., parallax_...)
// *********************************************************
int idx = 1;
aiMaterial *mat = (aiMaterial *)curMat;
if (curMatFlags & AI_IRRMESH_MAT_lightmap) { VertexFormat vertexFormat;
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0)); // Determine the file format
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) { pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0)); if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) { curUV2s.reserve(vertexCount);
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1)); vertexFormat = VertexFormat::t2coord;
} if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
} // *********************************************************
} else if (!ASSIMP_stricmp("tangents", t.name())) { // We have a second texture! So use this UV channel
curTangents.reserve(num); // for it. The 2nd texture can be either a normal
curBitangents.reserve(num); // texture (solid_2layer or lightmap_xxx) or a normal
vertexFormat = 2; // map (normal_..., parallax_...)
} else if (ASSIMP_stricmp("standard", t.name())) { // *********************************************************
releaseMaterial(&curMat); int idx = 1;
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format"); aiMaterial *mat = (aiMaterial *)curMat;
} 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");
}
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 // We know what format buffer is, collect numbers
curMesh = new aiMesh(); ParseBufferVertices(verticesNode.text().get(), vertexFormat,
curVertices, curNormals,
curTangents, curBitangents,
curUVs, curUV2s, curColors, useColors);
}
// allocate storage for all faces // Get indices
pugi::xml_attribute attr = child.attribute("indexCount"); // At this point we have some vertices and a valid material
curMesh->mNumVertices = attr.as_int(); // Collect indices and create aiMesh at the same time
if (!curMesh->mNumVertices) { pugi::xml_node indicesNode = bufferNode.child("indices");
// This is possible ... remove the mesh from the list and skip further reading if (indicesNode) {
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices"); // start a new mesh
curMesh = new aiMesh();
// mesh - away // allocate storage for all faces
releaseMesh(&curMesh); 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 // mesh - away
releaseMaterial(&curMat); releaseMesh(&curMesh);
textMeaning = 0; // material - away
continue; releaseMaterial(&curMat);
} continue; // Go to next buffer
}
if (curMesh->mNumVertices % 3) { if (curMesh->mNumVertices % 3) {
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3"); ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
} }
curMesh->mNumFaces = curMesh->mNumVertices / 3; curMesh->mNumFaces = curMesh->mNumVertices / 3;
curMesh->mFaces = new aiFace[curMesh->mNumFaces]; curMesh->mFaces = new aiFace[curMesh->mNumFaces];
// setup some members // setup some members
curMesh->mMaterialIndex = (unsigned int)materials.size(); curMesh->mMaterialIndex = (unsigned int)materials.size();
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// allocate storage for all vertices // allocate storage for all vertices
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices]; curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
if (curNormals.size() == curVertices.size()) { if (curNormals.size() == curVertices.size()) {
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices]; curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
} }
if (curTangents.size() == curVertices.size()) { if (curTangents.size() == curVertices.size()) {
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices]; curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
} }
if (curBitangents.size() == curVertices.size()) { if (curBitangents.size() == curVertices.size()) {
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices]; curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
} }
if (curColors.size() == curVertices.size() && useColors) { if (curColors.size() == curVertices.size() && useColors) {
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices]; curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
} }
if (curUVs.size() == curVertices.size()) { if (curUVs.size() == curVertices.size()) {
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
} }
if (curUV2s.size() == curVertices.size()) { if (curUV2s.size() == curVertices.size()) {
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices]; curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
} }
}
//break;
//case EXN_TEXT: { // read indices
const char *sz = child.child_value(); aiFace *curFace = curMesh->mFaces;
if (textMeaning == 1) { aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
textMeaning = 0;
// read vertices aiVector3D *pcV = curMesh->mVertices;
do { aiVector3D *pcN = curMesh->mNormals;
SkipSpacesAndLineEnd(&sz); aiVector3D *pcT = curMesh->mTangents;
aiVector3D temp; aiVector3D *pcB = curMesh->mBitangents;
aiColor4D c; aiColor4D *pcC0 = curMesh->mColors[0];
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
// Read the vertex position unsigned int curIdx = 0;
sz = fast_atoreal_move<float>(sz, (float &)temp.x); unsigned int total = 0;
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y); // NOTE this might explode for UTF-16 and wchars
SkipSpaces(&sz); 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); // Read index base 10
SkipSpaces(&sz); // function advances the pointer
curVertices.push_back(temp); unsigned int idx = strtoul10(sz, &sz);
if (idx >= curVertices.size()) {
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0;
}
// Read the vertex normals // make up our own indices?
sz = fast_atoreal_move<float>(sz, (float &)temp.x); curFace->mIndices[curIdx] = total++;
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y); // Copy over data to aiMesh
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.z); // start new face
SkipSpaces(&sz); if (++curIdx == 3) {
curNormals.push_back(temp); ++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 // Finish processing the mesh - do some small material workarounds
uint32_t clr = strtoul16(sz, &sz); if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
ColorFromARGBPacked(clr, c); // 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)) // end of previous buffer. A material and a mesh should be there
useColors = true; 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); // If one is empty then so is the other
SkipSpaces(&sz); if (materials.empty() || meshes.empty()) {
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
}
// read the first UV coordinate set // now generate the output scene
sz = fast_atoreal_move<float>(sz, (float &)temp.x); pScene->mNumMeshes = (unsigned int)meshes.size();
SkipSpaces(&sz); 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); // clean this value ...
SkipSpaces(&sz); pScene->mMeshes[i]->mNumUVComponents[3] = 0;
temp.z = 0.f; }
temp.y = 1.f - temp.y; // DX to OGL
curUVs.push_back(temp);
// read the (optional) second UV coordinate set pScene->mNumMaterials = (unsigned int)materials.size();
if (vertexFormat == 1) { pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
sz = fast_atoreal_move<float>(sz, (float &)temp.x); ::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y); pScene->mRootNode = new aiNode();
temp.y = 1.f - temp.y; // DX to OGL pScene->mRootNode->mName.Set("<IRRMesh>");
curUV2s.push_back(temp); pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
} pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
// read optional tangent and bitangent vectors
else if (vertexFormat == 2) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z); for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
SkipSpaces(&sz); pScene->mRootNode->mMeshes[i] = i;
};
}
sz = fast_atoreal_move<float>(sz, (float &)temp.y); void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
SkipSpaces(&sz); std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
temp.y *= -1.0f; std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
curTangents.push_back(temp); std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors) {
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
aiVector3D temp;
aiColor4D c;
// bitangents // Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x); sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz); SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z); sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz); SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y); sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz); SkipSpaces(&sz);
temp.y *= -1.0f; vertices.push_back(temp);
curBitangents.push_back(temp);
}
}
/* IMPORTANT: We assume that each vertex is specified in one // Read the vertex normals
line. So we can skip the rest of the line - unknown vertex sz = fast_atoreal_move<float>(sz, (float &)temp.x);
elements are ignored. SkipSpaces(&sz);
*/
while (SkipLine(&sz)); sz = fast_atoreal_move<float>(sz, (float &)temp.y);
} else if (textMeaning == 2) { SkipSpaces(&sz);
textMeaning = 0;
// read indices sz = fast_atoreal_move<float>(sz, (float &)temp.z);
aiFace *curFace = curMesh->mFaces; SkipSpaces(&sz);
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces; normals.push_back(temp);
aiVector3D *pcV = curMesh->mVertices; // read the vertex colors
aiVector3D *pcN = curMesh->mNormals; uint32_t clr = strtoul16(sz, &sz);
aiVector3D *pcT = curMesh->mTangents; ColorFromARGBPacked(clr, c);
aiVector3D *pcB = curMesh->mBitangents;
aiColor4D *pcC0 = curMesh->mColors[0];
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
unsigned int curIdx = 0; // If we're pushing more than one distinct color
unsigned int total = 0; if (!colors.empty() && c != *(colors.end() - 1))
while (SkipSpacesAndLineEnd(&sz)) { useColors = true;
if (curFace >= faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break;
}
if (!curIdx) {
curFace->mNumIndices = 3;
curFace->mIndices = new unsigned int[3];
}
unsigned int idx = strtoul10(sz, &sz); colors.push_back(c);
if (idx >= curVertices.size()) { SkipSpaces(&sz);
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0;
}
curFace->mIndices[curIdx] = total++; // read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
*pcV++ = curVertices[idx]; sz = fast_atoreal_move<float>(sz, (float &)temp.y);
if (pcN) *pcN++ = curNormals[idx]; SkipSpaces(&sz);
if (pcT) *pcT++ = curTangents[idx]; temp.z = 0.f;
if (pcB) *pcB++ = curBitangents[idx]; temp.y = 1.f - temp.y; // DX to OGL
if (pcC0) *pcC0++ = curColors[idx]; UVs.push_back(temp);
if (pcT0) *pcT0++ = curUVs[idx];
if (pcT1) *pcT1++ = curUV2s[idx];
if (++curIdx == 3) { // NOTE these correspond to specific S3DVertex* structs in irr sourcecode
++curFace; // So by definition, all buffers have either UV2 or tangents or neither
curIdx = 0; // 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) sz = fast_atoreal_move<float>(sz, (float &)temp.y);
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices"); 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 sz = fast_atoreal_move<float>(sz, (float &)temp.z);
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) { SkipSpaces(&sz);
// 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);
}
}
}
}
// End of the last buffer. A material and a mesh should be there sz = fast_atoreal_move<float>(sz, (float &)temp.y);
if (curMat || curMesh) { SkipSpaces(&sz);
if (!curMat || !curMesh) { temp.y *= -1.0f;
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); tangents.push_back(temp);
releaseMaterial(&curMat);
releaseMesh(&curMesh);
} else {
materials.push_back(curMat);
meshes.push_back(curMesh);
}
}
if (materials.empty()) { // bitangents
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file"); sz = fast_atoreal_move<float>(sz, (float &)temp.x);
} SkipSpaces(&sz);
// now generate the output scene sz = fast_atoreal_move<float>(sz, (float &)temp.z);
pScene->mNumMeshes = (unsigned int)meshes.size(); SkipSpaces(&sz);
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mMeshes[i] = meshes[i];
// clean this value ... sz = fast_atoreal_move<float>(sz, (float &)temp.y);
pScene->mMeshes[i]->mNumUVComponents[3] = 0; SkipSpaces(&sz);
} temp.y *= -1.0f;
bitangents.push_back(temp);
pScene->mNumMaterials = (unsigned int)materials.size(); }
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; } while (SkipLine(&sz));
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials); /* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
pScene->mRootNode = new aiNode(); elements are ignored.
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;
}
} }
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER #endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

View File

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

View File

@ -43,302 +43,302 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Shared utilities for the IRR and IRRMESH loaders * @brief Shared utilities for the IRR and IRRMESH loaders
*/ */
//This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted. // This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER)) #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
#include "IRRShared.h" #include "IRRShared.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/DefaultLogger.hpp>
using namespace Assimp; using namespace Assimp;
// Transformation matrix to convert from Assimp to IRR space // Transformation matrix to convert from Assimp to IRR space
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 ( const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 0.0f, 0.0f, 1.0f);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a property in hexadecimal format (i.e. ffffffff) // read a property in hexadecimal format (i.e. ffffffff)
void IrrlichtBase::ReadHexProperty(HexProperty &out ) { void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : hexnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string( attrib.value() ); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(),"value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the hexadecimal value // parse the hexadecimal value
out.value = strtoul16(attrib.name()); out.value = strtoul16(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a decimal property // read a decimal property
void IrrlichtBase::ReadIntProperty(IntProperty & out) { void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : intnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.value(),"value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the int value // parse the int value
out.value = strtol10(attrib.name()); out.value = strtol10(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a string property // read a string property
void IrrlichtBase::ReadStringProperty( StringProperty& out) { void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : stringnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// simple copy the string // simple copy the string
out.value = std::string(attrib.value()); out.value = std::string(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a boolean property // read a boolean property
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) { void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : boolnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")){ if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// true or false, case insensitive // true or false, case insensitive
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true); out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a float property // read a float property
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) { void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : floatnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// just parse the float // just parse the float
out.value = fast_atof(attrib.value()); out.value = fast_atof(attrib.value());
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a vector property // read a vector property
void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) { void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
for (pugi::xml_attribute attrib : mNode->attributes()) { for (pugi::xml_attribute attrib : vectornode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) { if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value()); out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) { } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// three floats, separated with commas // three floats, separated with commas
const char *ptr = attrib.value(); const char *ptr = attrib.value();
SkipSpaces(&ptr); SkipSpaces(&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) { if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else { } else {
SkipSpaces(ptr + 1, &ptr); SkipSpaces(ptr + 1, &ptr);
} }
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) { if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else { } else {
SkipSpaces(ptr + 1, &ptr); SkipSpaces(ptr + 1, &ptr);
} }
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z ); ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a string to a proper aiMappingMode // Convert a string to a proper aiMappingMode
int ConvertMappingMode(const std::string& mode) { int ConvertMappingMode(const std::string &mode) {
if (mode == "texture_clamp_repeat") { if (mode == "texture_clamp_repeat") {
return aiTextureMapMode_Wrap; return aiTextureMapMode_Wrap;
} else if (mode == "texture_clamp_mirror") { } else if (mode == "texture_clamp_mirror") {
return aiTextureMapMode_Mirror; return aiTextureMapMode_Mirror;
} }
return aiTextureMapMode_Clamp; return aiTextureMapMode_Clamp;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Parse a material from the XML file // Parse a material from the XML file
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) { aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
aiMaterial* mat = new aiMaterial(); aiMaterial *mat = new aiMaterial();
aiColor4D clr; aiColor4D clr;
aiString s; aiString s;
matFlags = 0; // zero output flags 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; unsigned int nd = 0;
for (pugi::xml_node child : mNode->children()) { for (pugi::xml_node child : materialNode.children()) {
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
HexProperty prop; HexProperty prop;
ReadHexProperty(prop); ReadHexProperty(prop, child);
if (prop.name == "Diffuse") { if (prop.name == "Diffuse") {
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
} else if (prop.name == "Ambient") { } else if (prop.name == "Ambient") {
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
} else if (prop.name == "Specular") { } else if (prop.name == "Specular") {
ColorFromARGBPacked(prop.value, clr); ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
} }
// NOTE: The 'emissive' property causes problems. It is // NOTE: The 'emissive' property causes problems. It is
// often != 0, even if there is obviously no light // often != 0, even if there is obviously no light
// emitted by the described surface. In fact I think // emitted by the described surface. In fact I think
// IRRLICHT ignores this property, too. // IRRLICHT ignores this property, too.
#if 0 #if 0
else if (prop.name == "Emissive") { else if (prop.name == "Emissive") {
ColorFromARGBPacked(prop.value,clr); ColorFromARGBPacked(prop.value,clr);
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE); mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
} }
#endif #endif
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties } else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop, child);
if (prop.name == "Shininess") { if (prop.name == "Shininess") {
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS); mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
} }
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties } else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop, child);
if (prop.name == "Wireframe") { if (prop.name == "Wireframe") {
int val = (prop.value ? true : false); int val = (prop.value ? true : false);
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME); mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
} else if (prop.name == "GouraudShading") { } else if (prop.name == "GouraudShading") {
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading); int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL); mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
} else if (prop.name == "BackfaceCulling") { } else if (prop.name == "BackfaceCulling") {
int val = (!prop.value); int val = (!prop.value);
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED); mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
} }
} else if (!ASSIMP_stricmp(child.name(), "texture") || } else if (!ASSIMP_stricmp(child.name(), "texture") ||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop, child);
if (prop.value.length()) { if (prop.value.length()) {
// material type (shader) // material type (shader)
if (prop.name == "Type") { if (prop.name == "Type") {
if (prop.value == "solid") { if (prop.value == "solid") {
// default material ... // default material ...
} else if (prop.value == "trans_vertex_alpha") { } else if (prop.value == "trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha; matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
} else if (prop.value == "lightmap") { } else if (prop.value == "lightmap") {
matFlags = AI_IRRMESH_MAT_lightmap; matFlags = AI_IRRMESH_MAT_lightmap;
} else if (prop.value == "solid_2layer") { } else if (prop.value == "solid_2layer") {
matFlags = AI_IRRMESH_MAT_solid_2layer; matFlags = AI_IRRMESH_MAT_solid_2layer;
} else if (prop.value == "lightmap_m2") { } else if (prop.value == "lightmap_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_m2; matFlags = AI_IRRMESH_MAT_lightmap_m2;
} else if (prop.value == "lightmap_m4") { } else if (prop.value == "lightmap_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_m4; matFlags = AI_IRRMESH_MAT_lightmap_m4;
} else if (prop.value == "lightmap_light") { } else if (prop.value == "lightmap_light") {
matFlags = AI_IRRMESH_MAT_lightmap_light; matFlags = AI_IRRMESH_MAT_lightmap_light;
} else if (prop.value == "lightmap_light_m2") { } else if (prop.value == "lightmap_light_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m2; matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
} else if (prop.value == "lightmap_light_m4") { } else if (prop.value == "lightmap_light_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m4; matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
} else if (prop.value == "lightmap_add") { } else if (prop.value == "lightmap_add") {
matFlags = AI_IRRMESH_MAT_lightmap_add; matFlags = AI_IRRMESH_MAT_lightmap_add;
} else if (prop.value == "normalmap_solid" || } else if (prop.value == "normalmap_solid" ||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
matFlags = AI_IRRMESH_MAT_normalmap_solid; matFlags = AI_IRRMESH_MAT_normalmap_solid;
} else if (prop.value == "normalmap_trans_vertex_alpha" || } else if (prop.value == "normalmap_trans_vertex_alpha" ||
prop.value == "parallaxmap_trans_vertex_alpha") { prop.value == "parallaxmap_trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_normalmap_tva; matFlags = AI_IRRMESH_MAT_normalmap_tva;
} else if (prop.value == "normalmap_trans_add" || } else if (prop.value == "normalmap_trans_add" ||
prop.value == "parallaxmap_trans_add") { prop.value == "parallaxmap_trans_add") {
matFlags = AI_IRRMESH_MAT_normalmap_ta; matFlags = AI_IRRMESH_MAT_normalmap_ta;
} else { } else {
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value); ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
} }
} }
// Up to 4 texture channels are supported // Up to 4 texture channels are supported
if (prop.name == "Texture1") { if (prop.name == "Texture1") {
// Always accept the primary texture channel // Always accept the primary texture channel
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
} else if (prop.name == "Texture2" && cnt == 1) { } else if (prop.name == "Texture2" && cnt == 1) {
// 2-layer material lightmapped? // 2-layer material lightmapped?
if (matFlags & AI_IRRMESH_MAT_lightmap) { if (matFlags & AI_IRRMESH_MAT_lightmap) {
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping } else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
++nd; ++nd;
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else { } else {
ASSIMP_LOG_WARN("IRRmat: Skipping second texture"); ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
} }
} else if (prop.name == "Texture3" && cnt == 2) { } else if (prop.name == "Texture3" && cnt == 2) {
// Irrlicht does not seem to use these channels. // Irrlicht does not seem to use these channels.
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
} else if (prop.name == "Texture4" && cnt == 3) { } else if (prop.name == "Texture4" && cnt == 3) {
// Irrlicht does not seem to use these channels. // Irrlicht does not seem to use these channels.
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2)); mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
} }
// Texture mapping options // Texture mapping options
if (prop.name == "TextureWrap1" && cnt >= 1) { if (prop.name == "TextureWrap1" && cnt >= 1) {
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
} else if (prop.name == "TextureWrap2" && cnt >= 2) { } else if (prop.name == "TextureWrap2" && cnt >= 2) {
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
if (matFlags & AI_IRRMESH_MAT_lightmap) { if (matFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) { } 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_U_NORMALS(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { } 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_U_DIFFUSE(1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
} }
} else if (prop.name == "TextureWrap3" && cnt >= 3) { } else if (prop.name == "TextureWrap3" && cnt >= 3) {
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
} else if (prop.name == "TextureWrap4" && cnt >= 4) { } else if (prop.name == "TextureWrap4" && cnt >= 4) {
int map = ConvertMappingMode(prop.value); int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2)); mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
} }
} }
} }
//break; // break;
/*case EXN_ELEMENT_END: /*case EXN_ELEMENT_END:
// Assume there are no further nested nodes in <material> elements // Assume there are no further nested nodes in <material> elements
if ( !ASSIMP_stricmp(reader->getNodeName(),"material") || if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
@ -378,8 +378,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
break; 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; return mat;
} }

View File

@ -1,8 +1,8 @@
/** @file IRRShared.h /** @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 #ifndef INCLUDED_AI_IRRSHARED_H
#define INCLUDED_AI_IRRSHARED_H #define INCLUDED_AI_IRRSHARED_H
@ -58,8 +58,7 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
*/ */
class IrrlichtBase { class IrrlichtBase {
protected: protected:
IrrlichtBase() : IrrlichtBase() {
mNode(nullptr) {
// empty // empty
} }
@ -82,25 +81,25 @@ protected:
/// XML reader instance /// XML reader instance
XmlParser mParser; XmlParser mParser;
pugi::xml_node *mNode;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Parse a material description from the XML /** Parse a material description from the XML
* @return The created material * @return The created material
* @param matFlags Receives AI_IRRMESH_MAT_XX flags * @param matFlags Receives AI_IRRMESH_MAT_XX flags
*/ */
aiMaterial *ParseMaterial(unsigned int &matFlags); aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Read a property of the specified type from the current XML element. /** Read a property of the specified type from the current XML element.
* @param out Receives output data * @param out Receives output data
* @param node XML attribute element containing data
*/ */
void ReadHexProperty(HexProperty &out); void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
void ReadStringProperty(StringProperty &out); void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
void ReadBoolProperty(BoolProperty &out); void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
void ReadFloatProperty(FloatProperty &out); void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
void ReadVectorProperty(VectorProperty &out); void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
void ReadIntProperty(IntProperty &out); void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -51,65 +51,56 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "LWOLoader.h" #include "LWOLoader.h"
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBFile() void LWOImporter::LoadLWOBFile() {
{
LE_NCONST uint8_t* const end = mFileBuffer + fileSize; LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
bool running = true; bool running = true;
while (running) while (running) {
{ if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; break;
const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
if (mFileBuffer + head.length > end) if (mFileBuffer + head.length > end) {
{
throw DeadlyImportError("LWOB: Invalid chunk length"); throw DeadlyImportError("LWOB: Invalid chunk length");
break;
} }
uint8_t* const next = mFileBuffer+head.length; uint8_t* const next = mFileBuffer+head.length;
switch (head.type) switch (head.type) {
{
// vertex list // vertex list
case AI_LWO_PNTS: case AI_LWO_PNTS: {
{
if (!mCurLayer->mTempPoints.empty()) if (!mCurLayer->mTempPoints.empty())
ASSIMP_LOG_WARN("LWO: PNTS chunk encountered twice"); ASSIMP_LOG_WARN("LWO: PNTS chunk encountered twice");
else LoadLWOPoints(head.length); else
break; LoadLWOPoints(head.length);
} } break;
// face list case AI_LWO_POLS: { // face list
case AI_LWO_POLS: if (!mCurLayer->mFaces.empty())
{ ASSIMP_LOG_WARN("LWO: POLS chunk encountered twice");
else
LoadLWOBPolygons(head.length);
} break;
case AI_LWO_SRFS: // list of tags
{
if (!mTags->empty())
ASSIMP_LOG_WARN("LWO: SRFS chunk encountered twice");
else
LoadLWOTags(head.length);
} break;
if (!mCurLayer->mFaces.empty()) case AI_LWO_SURF: // surface chunk
ASSIMP_LOG_WARN("LWO: POLS chunk encountered twice"); {
else LoadLWOBPolygons(head.length); LoadLWOBSurface(head.length);
break; } break;
}
// list of tags
case AI_LWO_SRFS:
{
if (!mTags->empty())
ASSIMP_LOG_WARN("LWO: SRFS chunk encountered twice");
else LoadLWOTags(head.length);
break;
}
// surface chunk default:
case AI_LWO_SURF:
{
LoadLWOBSurface(head.length);
break; break;
}
} }
mFileBuffer = next; mFileBuffer = next;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBPolygons(unsigned int length) void LWOImporter::LoadLWOBPolygons(unsigned int length) {
{
// first find out how many faces and vertices we'll finally need // first find out how many faces and vertices we'll finally need
LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer; LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer;
@ -124,8 +115,7 @@ void LWOImporter::LoadLWOBPolygons(unsigned int length)
CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end); CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end);
// allocate the output array and copy face indices // allocate the output array and copy face indices
if (iNumFaces) if (iNumFaces) {
{
cursor = (LE_NCONST uint16_t*)mFileBuffer; cursor = (LE_NCONST uint16_t*)mFileBuffer;
mCurLayer->mFaces.resize(iNumFaces); mCurLayer->mFaces.resize(iNumFaces);
@ -136,10 +126,8 @@ void LWOImporter::LoadLWOBPolygons(unsigned int length)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces, void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces,
LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) {
{ while (cursor < end && max--) {
while (cursor < end && max--)
{
uint16_t numIndices; uint16_t numIndices;
// must have 2 shorts left for numIndices and surface // must have 2 shorts left for numIndices and surface
if (end - cursor < 2) { if (end - cursor < 2) {
@ -155,8 +143,7 @@ void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& face
cursor += numIndices; cursor += numIndices;
int16_t surface; int16_t surface;
::memcpy(&surface, cursor++, 2); ::memcpy(&surface, cursor++, 2);
if (surface < 0) if (surface < 0) {
{
// there are detail polygons // there are detail polygons
::memcpy(&numIndices, cursor++, 2); ::memcpy(&numIndices, cursor++, 2);
CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices); CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices);
@ -168,18 +155,14 @@ void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& face
void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it, void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
LE_NCONST uint16_t*& cursor, LE_NCONST uint16_t*& cursor,
const uint16_t* const end, const uint16_t* const end,
unsigned int max) unsigned int max) {
{ while (cursor < end && max--) {
while (cursor < end && max--)
{
LWO::Face& face = *it;++it; LWO::Face& face = *it;++it;
uint16_t numIndices; uint16_t numIndices;
::memcpy(&numIndices, cursor++, 2); ::memcpy(&numIndices, cursor++, 2);
face.mNumIndices = numIndices; face.mNumIndices = numIndices;
if(face.mNumIndices) if(face.mNumIndices) {
{ if (cursor + face.mNumIndices >= end) {
if (cursor + face.mNumIndices >= end)
{
break; break;
} }
face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices = new unsigned int[face.mNumIndices];
@ -188,8 +171,7 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
uint16_t index; uint16_t index;
::memcpy(&index, cursor++, 2); ::memcpy(&index, cursor++, 2);
mi = index; mi = index;
if (mi > mCurLayer->mTempPoints.size()) if (mi > mCurLayer->mTempPoints.size()) {
{
ASSIMP_LOG_WARN("LWOB: face index is out of range"); ASSIMP_LOG_WARN("LWOB: face index is out of range");
mi = (unsigned int)mCurLayer->mTempPoints.size()-1; mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
} }
@ -199,15 +181,13 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
} }
int16_t surface; int16_t surface;
::memcpy(&surface, cursor++, 2); ::memcpy(&surface, cursor++, 2);
if (surface < 0) if (surface < 0) {
{
surface = -surface; surface = -surface;
// there are detail polygons. // there are detail polygons.
uint16_t numPolygons; uint16_t numPolygons;
::memcpy(&numPolygons, cursor++, 2); ::memcpy(&numPolygons, cursor++, 2);
if (cursor < end) if (cursor < end) {
{
CopyFaceIndicesLWOB(it,cursor,end,numPolygons); CopyFaceIndicesLWOB(it,cursor,end,numPolygons);
} }
} }
@ -216,8 +196,7 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size) LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size) {
{
list.emplace_back(); list.emplace_back();
LWO::Texture* tex = &list.back(); LWO::Texture* tex = &list.back();
@ -225,8 +204,7 @@ LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned i
GetS0(type,size); GetS0(type,size);
const char* s = type.c_str(); const char* s = type.c_str();
if(strstr(s, "Image Map")) if(strstr(s, "Image Map")) {
{
// Determine mapping type // Determine mapping type
if(strstr(s, "Planar")) if(strstr(s, "Planar"))
tex->mapMode = LWO::Texture::Planar; tex->mapMode = LWO::Texture::Planar;
@ -238,9 +216,7 @@ LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned i
tex->mapMode = LWO::Texture::Cubic; tex->mapMode = LWO::Texture::Cubic;
else if(strstr(s, "Front")) else if(strstr(s, "Front"))
tex->mapMode = LWO::Texture::FrontProjection; tex->mapMode = LWO::Texture::FrontProjection;
} } else {
else
{
// procedural or gradient, not supported // procedural or gradient, not supported
ASSIMP_LOG_ERROR("LWOB: Unsupported legacy texture: ", type); ASSIMP_LOG_ERROR("LWOB: Unsupported legacy texture: ", type);
} }
@ -249,8 +225,7 @@ LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned i
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBSurface(unsigned int size) void LWOImporter::LoadLWOBSurface(unsigned int size) {
{
LE_NCONST uint8_t* const end = mFileBuffer + size; LE_NCONST uint8_t* const end = mFileBuffer + size;
mSurfaces->push_back( LWO::Surface () ); mSurfaces->push_back( LWO::Surface () );
@ -278,148 +253,147 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
} }
uint8_t* const next = mFileBuffer+head.length; uint8_t* const next = mFileBuffer+head.length;
switch (head.type) switch (head.type) {
{ // diffuse color
// diffuse color case AI_LWO_COLR:
case AI_LWO_COLR: {
{ AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3);
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3); surf.mColor.r = GetU1() / 255.0f;
surf.mColor.r = GetU1() / 255.0f; surf.mColor.g = GetU1() / 255.0f;
surf.mColor.g = GetU1() / 255.0f; surf.mColor.b = GetU1() / 255.0f;
surf.mColor.b = GetU1() / 255.0f; break;
break;
}
// diffuse strength ...
case AI_LWO_DIFF:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2);
surf.mDiffuseValue = GetU2() / 255.0f;
break;
}
// specular strength ...
case AI_LWO_SPEC:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2);
surf.mSpecularValue = GetU2() / 255.0f;
break;
}
// luminosity ...
case AI_LWO_LUMI:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2);
surf.mLuminosity = GetU2() / 255.0f;
break;
}
// transparency
case AI_LWO_TRAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2);
surf.mTransparency = GetU2() / 255.0f;
break;
}
// surface flags
case AI_LWO_FLAG:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2);
uint16_t flag = GetU2();
if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f;
if (flag & 0x8 ) surf.mColorHighlights = 1.f;
if (flag & 0x100) surf.bDoubleSided = true;
break;
}
// maximum smoothing angle
case AI_LWO_SMAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
surf.mMaximumSmoothAngle = std::fabs( GetF4() );
break;
}
// glossiness
case AI_LWO_GLOS:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2);
surf.mGlossiness = (float)GetU2();
break;
}
// color texture
case AI_LWO_CTEX:
{
pTex = SetupNewTextureLWOB(surf.mColorTextures,
head.length);
break;
}
// diffuse texture
case AI_LWO_DTEX:
{
pTex = SetupNewTextureLWOB(surf.mDiffuseTextures,
head.length);
break;
}
// specular texture
case AI_LWO_STEX:
{
pTex = SetupNewTextureLWOB(surf.mSpecularTextures,
head.length);
break;
}
// bump texture
case AI_LWO_BTEX:
{
pTex = SetupNewTextureLWOB(surf.mBumpTextures,
head.length);
break;
}
// transparency texture
case AI_LWO_TTEX:
{
pTex = SetupNewTextureLWOB(surf.mOpacityTextures,
head.length);
break;
}
// texture path
case AI_LWO_TIMG:
{
if (pTex) {
GetS0(pTex->mFileName,head.length);
} else {
ASSIMP_LOG_WARN("LWOB: Unexpected TIMG chunk");
} }
break; // diffuse strength ...
} case AI_LWO_DIFF:
// texture strength {
case AI_LWO_TVAL: AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2);
{ surf.mDiffuseValue = GetU2() / 255.0f;
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1); break;
if (pTex) {
pTex->mStrength = (float)GetU1()/ 255.f;
} else {
ASSIMP_LOG_ERROR("LWOB: Unexpected TVAL chunk");
} }
break; // specular strength ...
} case AI_LWO_SPEC:
// texture flags {
case AI_LWO_TFLG: AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2);
{ surf.mSpecularValue = GetU2() / 255.0f;
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TFLG,2); break;
}
if (nullptr != pTex) { // luminosity ...
const uint16_t s = GetU2(); case AI_LWO_LUMI:
if (s & 1) {
pTex->majorAxis = LWO::Texture::AXIS_X; AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2);
else if (s & 2) surf.mLuminosity = GetU2() / 255.0f;
pTex->majorAxis = LWO::Texture::AXIS_Y; break;
else if (s & 4) }
pTex->majorAxis = LWO::Texture::AXIS_Z; // transparency
case AI_LWO_TRAN:
if (s & 16) { {
ASSIMP_LOG_WARN("LWOB: Ignoring \'negate\' flag on texture"); AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2);
surf.mTransparency = GetU2() / 255.0f;
break;
}
// surface flags
case AI_LWO_FLAG:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2);
uint16_t flag = GetU2();
if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f;
if (flag & 0x8 ) surf.mColorHighlights = 1.f;
if (flag & 0x100) surf.bDoubleSided = true;
break;
}
// maximum smoothing angle
case AI_LWO_SMAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
surf.mMaximumSmoothAngle = std::fabs( GetF4() );
break;
}
// glossiness
case AI_LWO_GLOS:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2);
surf.mGlossiness = (float)GetU2();
break;
}
// color texture
case AI_LWO_CTEX:
{
pTex = SetupNewTextureLWOB(surf.mColorTextures,
head.length);
break;
}
// diffuse texture
case AI_LWO_DTEX:
{
pTex = SetupNewTextureLWOB(surf.mDiffuseTextures,
head.length);
break;
}
// specular texture
case AI_LWO_STEX:
{
pTex = SetupNewTextureLWOB(surf.mSpecularTextures,
head.length);
break;
}
// bump texture
case AI_LWO_BTEX:
{
pTex = SetupNewTextureLWOB(surf.mBumpTextures,
head.length);
break;
}
// transparency texture
case AI_LWO_TTEX:
{
pTex = SetupNewTextureLWOB(surf.mOpacityTextures,
head.length);
break;
}
// texture path
case AI_LWO_TIMG:
{
if (pTex) {
GetS0(pTex->mFileName,head.length);
} else {
ASSIMP_LOG_WARN("LWOB: Unexpected TIMG chunk");
} }
break;
} }
else { // texture strength
ASSIMP_LOG_WARN("LWOB: Unexpected TFLG chunk"); case AI_LWO_TVAL:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1);
if (pTex) {
pTex->mStrength = (float)GetU1()/ 255.f;
} else {
ASSIMP_LOG_ERROR("LWOB: Unexpected TVAL chunk");
}
break;
}
// texture flags
case AI_LWO_TFLG:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TFLG,2);
if (nullptr != pTex) {
const uint16_t s = GetU2();
if (s & 1)
pTex->majorAxis = LWO::Texture::AXIS_X;
else if (s & 2)
pTex->majorAxis = LWO::Texture::AXIS_Y;
else if (s & 4)
pTex->majorAxis = LWO::Texture::AXIS_Z;
if (s & 16) {
ASSIMP_LOG_WARN("LWOB: Ignoring \'negate\' flag on texture");
}
}
else {
ASSIMP_LOG_WARN("LWOB: Unexpected TFLG chunk");
}
break;
} }
break;
}
} }
mFileBuffer = next; mFileBuffer = next;
} }

View File

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

View File

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

View File

@ -63,7 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"LightWave Scene Importer", "LightWave Scene Importer",
"", "",
"", "",
@ -139,10 +139,6 @@ LWSImporter::LWSImporter() :
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
LWSImporter::~LWSImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -632,18 +628,17 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
nodes.push_back(d); nodes.push_back(d);
} }
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'"); ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'");
} else {
// important: index of channel
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 // 'Envelope': a single animation channel
else if ((*it).tokens[0] == "Envelope") { else if ((*it).tokens[0] == "Envelope") {

View File

@ -174,7 +174,7 @@ struct NodeDesc {
class LWSImporter : public BaseImporter { class LWSImporter : public BaseImporter {
public: public:
LWSImporter(); LWSImporter();
~LWSImporter() override; ~LWSImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether we can read a specific file // Check whether we can read a specific file

View File

@ -85,7 +85,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
are listed in aiScene->mRootNode->children, but all without meshes are listed in aiScene->mRootNode->children, but all without meshes
*/ */
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Model 3D Importer", "Model 3D Importer",
"", "",
"", "",

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -41,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER #ifndef ASSIMP_BUILD_NO_MD2_IMPORTER
/** @file Implementation of the MD2 importer class */ /** @file Implementation of the MD2 importer class */
@ -65,7 +62,7 @@ using namespace Assimp::MD2;
# define ARRAYSIZE(_array) (int(sizeof(_array) / sizeof(_array[0]))) # define ARRAYSIZE(_array) (int(sizeof(_array) / sizeof(_array[0])))
#endif #endif
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Quake II Mesh Importer", "Quake II Mesh Importer",
"", "",
"", "",
@ -79,7 +76,7 @@ static const aiImporterDesc desc = {
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Helper function to lookup a normal in Quake 2's precalculated table // Helper function to lookup a normal in Quake 2's pre-calculated table
void MD2::LookupNormalIndex(uint8_t iNormalIndex,aiVector3D& vOut) void MD2::LookupNormalIndex(uint8_t iNormalIndex,aiVector3D& vOut)
{ {
// make sure the normal index has a valid value // make sure the normal index has a valid value
@ -100,10 +97,6 @@ MD2Importer::MD2Importer()
fileSize() fileSize()
{} {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MD2Importer::~MD2Importer() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const

View File

@ -63,7 +63,7 @@ using namespace MD2;
class MD2Importer : public BaseImporter { class MD2Importer : public BaseImporter {
public: public:
MD2Importer(); MD2Importer();
~MD2Importer() override; ~MD2Importer() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

@ -70,7 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Quake III Mesh Importer", "Quake III Mesh Importer",
"", "",
"", "",

View File

@ -64,7 +64,7 @@ using namespace Assimp;
// Minimum weight value. Weights inside [-n ... n] are ignored // Minimum weight value. Weights inside [-n ... n] are ignored
#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>() #define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Doom 3 / MD5 Mesh Importer", "Doom 3 / MD5 Mesh Importer",
"", "",
"", "",
@ -92,10 +92,6 @@ MD5Importer::MD5Importer() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MD5Importer::~MD5Importer() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {

View File

@ -65,7 +65,7 @@ using namespace Assimp::MD5;
class MD5Importer : public BaseImporter { class MD5Importer : public BaseImporter {
public: public:
MD5Importer(); MD5Importer();
~MD5Importer() override; ~MD5Importer() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2023, assimp team
All rights reserved. All rights reserved.
@ -87,7 +87,7 @@ MD5Parser::MD5Parser(char *_buffer, unsigned int _fileSize) : buffer(_buffer), b
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Report error to the log stream // Report error to the log stream
/*static*/ AI_WONT_RETURN void MD5Parser::ReportError(const char *error, unsigned int line) { AI_WONT_RETURN void MD5Parser::ReportError(const char *error, unsigned int line) {
char szBuffer[1024]; char szBuffer[1024];
::ai_snprintf(szBuffer, 1024, "[MD5] Line %u: %s", line, error); ::ai_snprintf(szBuffer, 1024, "[MD5] Line %u: %s", line, error);
throw DeadlyImportError(szBuffer); throw DeadlyImportError(szBuffer);
@ -95,7 +95,7 @@ MD5Parser::MD5Parser(char *_buffer, unsigned int _fileSize) : buffer(_buffer), b
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Report warning to the log stream // Report warning to the log stream
/*static*/ void MD5Parser::ReportWarning(const char *warn, unsigned int line) { void MD5Parser::ReportWarning(const char *warn, unsigned int line) {
char szBuffer[1024]; char szBuffer[1024];
::snprintf(szBuffer, sizeof(szBuffer), "[MD5] Line %u: %s", line, warn); ::snprintf(szBuffer, sizeof(szBuffer), "[MD5] Line %u: %s", line, warn);
ASSIMP_LOG_WARN(szBuffer); ASSIMP_LOG_WARN(szBuffer);
@ -122,8 +122,8 @@ void MD5Parser::ParseHeader() {
// print the command line options to the console // print the command line options to the console
// FIX: can break the log length limit, so we need to be careful // FIX: can break the log length limit, so we need to be careful
char *sz = buffer; char *sz = buffer;
while (!IsLineEnd(*buffer++)) while (!IsLineEnd(*buffer++));
;
ASSIMP_LOG_INFO(std::string(sz, std::min((uintptr_t)MAX_LOG_MESSAGE_LENGTH, (uintptr_t)(buffer - sz)))); ASSIMP_LOG_INFO(std::string(sz, std::min((uintptr_t)MAX_LOG_MESSAGE_LENGTH, (uintptr_t)(buffer - sz))));
SkipSpacesAndLineEnd(); SkipSpacesAndLineEnd();
} }
@ -138,18 +138,31 @@ bool MD5Parser::ParseSection(Section &out) {
char *sz = buffer; char *sz = buffer;
while (!IsSpaceOrNewLine(*buffer)) { while (!IsSpaceOrNewLine(*buffer)) {
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
} }
out.mName = std::string(sz, (uintptr_t)(buffer - sz)); out.mName = std::string(sz, (uintptr_t)(buffer - sz));
SkipSpaces(); while (IsSpace(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
bool running = true; bool running = true;
while (running) { while (running) {
if ('{' == *buffer) { if ('{' == *buffer) {
// it is a normal section so read all lines // it is a normal section so read all lines
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
bool run = true; bool run = true;
while (run) { while (run) {
if (!SkipSpacesAndLineEnd()) { while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
if ('\0' == *buffer) {
return false; // seems this was the last section return false; // seems this was the last section
} }
if ('}' == *buffer) { if ('}' == *buffer) {
@ -164,25 +177,39 @@ bool MD5Parser::ParseSection(Section &out) {
elem.szStart = buffer; elem.szStart = buffer;
// terminate the line with zero // terminate the line with zero
while (!IsLineEnd(*buffer)) while (!IsLineEnd(*buffer)) {
++buffer; ++buffer;
if (buffer == bufferEnd)
return false;
}
if (*buffer) { if (*buffer) {
++lineNumber; ++lineNumber;
*buffer++ = '\0'; *buffer++ = '\0';
if (buffer == bufferEnd)
return false;
} }
} }
break; break;
} else if (!IsSpaceOrNewLine(*buffer)) { } else if (!IsSpaceOrNewLine(*buffer)) {
// it is an element at global scope. Parse its value and go on // it is an element at global scope. Parse its value and go on
sz = buffer; sz = buffer;
while (!IsSpaceOrNewLine(*buffer++)) while (!IsSpaceOrNewLine(*buffer++)) {
; if (buffer == bufferEnd)
return false;
}
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz)); out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
continue; continue;
} }
break; break;
} }
return SkipSpacesAndLineEnd(); if (buffer == bufferEnd)
return false;
while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
return '\0' != *buffer;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -228,15 +255,20 @@ bool MD5Parser::ParseSection(Section &out) {
out.data[out.length] = '\0'; out.data[out.length] = '\0';
// parse a string, enclosed in quotation marks // parse a string, enclosed in quotation marks
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \ #define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
while ('\"' != *sz) \ out.length = 0; \
++sz; \ while ('\"' != *sz && '\0' != *sz) \
const char *szStart = ++sz; \ ++sz; \
while ('\"' != *sz) \ if ('\0' != *sz) { \
++sz; \ const char *szStart = ++sz; \
const char *szEnd = (sz++); \ while ('\"' != *sz && '\0' != *sz) \
out.length = (ai_uint32)(szEnd - szStart); \ ++sz; \
::memcpy(out.data, szStart, out.length); \ if ('\0' != *sz) { \
const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \
} \
} \
out.data[out.length] = '\0'; out.data[out.length] = '\0';
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// .MD5MESH parsing function // .MD5MESH parsing function

View File

@ -2,8 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2023, assimp team
All rights reserved. All rights reserved.
@ -93,7 +92,7 @@ struct Section {
std::string mName; std::string mName;
//! For global elements: the value of the element as string //! For global elements: the value of the element as string
//! Iif !length() the section is not a global element //! if !length() the section is not a global element
std::string mGlobalValue; std::string mGlobalValue;
}; };
@ -185,7 +184,7 @@ using FrameList = std::vector<FrameDesc>;
*/ */
struct VertexDesc { struct VertexDesc {
VertexDesc() AI_NO_EXCEPT VertexDesc() AI_NO_EXCEPT
: mFirstWeight(0), mNumWeights(0) { : mFirstWeight(0), mNumWeights(0) {
// empty // empty
} }
@ -349,61 +348,61 @@ public:
*/ */
MD5Parser(char* buffer, unsigned int fileSize); MD5Parser(char* buffer, unsigned int fileSize);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Report a specific error message and throw an exception /** Report a specific error message and throw an exception
* @param error Error message to be reported * @param error Error message to be reported
* @param line Index of the line where the error occurred * @param line Index of the line where the error occurred
*/ */
AI_WONT_RETURN static void ReportError (const char* error, unsigned int line) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN static void ReportError(const char* error, unsigned int line) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Report a specific warning /** Report a specific warning
* @param warn Warn message to be reported * @param warn Warn message to be reported
* @param line Index of the line where the error occurred * @param line Index of the line where the error occurred
*/ */
static void ReportWarning (const char* warn, unsigned int line); static void ReportWarning(const char* warn, unsigned int line);
// -------------------------------------------------------------------
/** Report a specific error
* @param error Error message to be reported
*/
AI_WONT_RETURN void ReportError (const char* error) AI_WONT_RETURN_SUFFIX;
void ReportError (const char* error) { // -------------------------------------------------------------------
return ReportError(error, lineNumber); /** Report a specific warning
} * @param error Warn message to be reported
*/
void ReportWarning (const char* warn) { void ReportWarning (const char* warn);
return ReportWarning(warn, lineNumber);
}
//! List of all sections which have been read //! List of all sections which have been read
SectionList mSections; SectionList mSections;
private: private:
// -------------------------------------------------------------------
/** Parses a file section. The current file pointer must be outside
* of a section.
* @param out Receives the section data
* @return true if the end of the file has been reached
* @throws ImportErrorException if an error occurs
*/
bool ParseSection(Section& out); bool ParseSection(Section& out);
// -------------------------------------------------------------------
/** Parses the file header
* @throws ImportErrorException if an error occurs
*/
void ParseHeader(); void ParseHeader();
bool SkipLine(const char* in, const char** out); bool SkipLine(const char* in, const char** out);
bool SkipLine( ); bool SkipLine( );
bool SkipSpacesAndLineEnd( const char* in, const char** out); bool SkipSpacesAndLineEnd( const char* in, const char** out);
bool SkipSpacesAndLineEnd(); bool SkipSpacesAndLineEnd();
bool SkipSpaces(); bool SkipSpaces();
private:
char* buffer; char* buffer;
char* bufferEnd; char* bufferEnd;
unsigned int fileSize; unsigned int fileSize;
unsigned int lineNumber; unsigned int lineNumber;
}; };
// -------------------------------------------------------------------
inline void MD5Parser::ReportWarning (const char* warn) {
return ReportWarning(warn, lineNumber);
}
// -------------------------------------------------------------------
inline void MD5Parser::ReportError(const char* error) {
ReportError(error, lineNumber);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline bool MD5Parser::SkipLine(const char* in, const char** out) { inline bool MD5Parser::SkipLine(const char* in, const char** out) {
++lineNumber; ++lineNumber;
@ -417,18 +416,24 @@ inline bool MD5Parser::SkipLine( ) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline bool MD5Parser::SkipSpacesAndLineEnd( const char* in, const char** out) { inline bool MD5Parser::SkipSpacesAndLineEnd( const char* in, const char** out) {
bool bHad = false; if (in == bufferEnd) {
bool running = true; *out = in;
return false;
}
bool bHad = false, running = true;
while (running) { while (running) {
if( *in == '\r' || *in == '\n') { if( *in == '\r' || *in == '\n') {
// we open files in binary mode, so there could be \r\n sequences ... // we open files in binary mode, so there could be \r\n sequences ...
if (!bHad) { if (!bHad) {
bHad = true; bHad = true;
++lineNumber; ++lineNumber;
} }
} else if (*in == '\t' || *in == ' ') {
bHad = false;
} else {
break;
} }
else if (*in == '\t' || *in == ' ')bHad = false;
else break;
++in; ++in;
if (in == bufferEnd) { if (in == bufferEnd) {
break; break;

View File

@ -60,7 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
using namespace Assimp::MDC; using namespace Assimp::MDC;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Return To Castle Wolfenstein Mesh Importer", "Return To Castle Wolfenstein Mesh Importer",
"", "",
"", "",
@ -103,10 +103,6 @@ MDCImporter::MDCImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MDCImporter::~MDCImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {

View File

@ -62,7 +62,7 @@ using namespace MDC;
class MDCImporter : public BaseImporter { class MDCImporter : public BaseImporter {
public: public:
MDCImporter(); MDCImporter();
~MDCImporter() override; ~MDCImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

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

View File

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

View File

@ -65,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static const aiImporterDesc desc = { static constexpr aiImporterDesc desc = {
"Quake Mesh / 3D GameStudio Mesh Importer", "Quake Mesh / 3D GameStudio Mesh Importer",
"", "",
"", "",
@ -96,10 +96,6 @@ MDLImporter::MDLImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MDLImporter::~MDLImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
@ -271,10 +267,16 @@ void MDLImporter::InternReadFile(const std::string &pFile,
} }
} }
// ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range
bool MDLImporter::IsPosValid(const void *szPos) const {
return szPos && (const unsigned char *)szPos <= this->mBuffer + this->iFileSize && szPos >= this->mBuffer;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range // Check whether we're still inside the valid file range
void MDLImporter::SizeCheck(const void *szPos) { void MDLImporter::SizeCheck(const void *szPos) {
if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize) { if (!IsPosValid(szPos)) {
throw DeadlyImportError("Invalid MDL file. The file is too small " throw DeadlyImportError("Invalid MDL file. The file is too small "
"or contains invalid data."); "or contains invalid data.");
} }
@ -284,7 +286,7 @@ void MDLImporter::SizeCheck(const void *szPos) {
// Just for debugging purposes // Just for debugging purposes
void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) { void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
ai_assert(nullptr != szFile); ai_assert(nullptr != szFile);
if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) { if (!IsPosValid(szPos)) {
// remove a directory if there is one // remove a directory if there is one
const char *szFilePtr = ::strrchr(szFile, '\\'); const char *szFilePtr = ::strrchr(szFile, '\\');
if (!szFilePtr) { if (!szFilePtr) {
@ -975,7 +977,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones)
} }
// store the name of the bone // store the name of the bone
pcOutBone->mName.length = (size_t)iMaxLen; pcOutBone->mName.length = static_cast<ai_uint32>(iMaxLen);
::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length); ::memcpy(pcOutBone->mName.data, pcBone->name, pcOutBone->mName.length);
pcOutBone->mName.data[pcOutBone->mName.length] = '\0'; pcOutBone->mName.data[pcOutBone->mName.length] = '\0';
} }

View File

@ -39,10 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/// @file MDLLoader.h
/** @file MDLLoader.h /// @brief Declaration of the loader for MDL files
* @brief Declaration of the loader for MDL files
*/
#pragma once #pragma once
#ifndef AI_MDLLOADER_H_INCLUDED #ifndef AI_MDLLOADER_H_INCLUDED
#define AI_MDLLOADER_H_INCLUDED #define AI_MDLLOADER_H_INCLUDED
@ -83,11 +81,10 @@ using namespace MDL;
* them all with a single 1000-line function-beast. However, it has been * them all with a single 1000-line function-beast. However, it has been
* split into several code paths to make the code easier to read and maintain. * split into several code paths to make the code easier to read and maintain.
*/ */
class MDLImporter : public BaseImporter class MDLImporter : public BaseImporter {
{
public: public:
MDLImporter(); MDLImporter();
~MDLImporter() override; ~MDLImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
@ -139,7 +136,7 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Import a CS:S/HL2 MDL file (not fully implemented) /** Import a CS:S/HL2 MDL file (not fully implemented)
*/ */
void InternReadFile_HL2( ); AI_WONT_RETURN void InternReadFile_HL2( ) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Check whether a given position is inside the valid range /** Check whether a given position is inside the valid range
@ -150,6 +147,7 @@ protected:
*/ */
void SizeCheck(const void* szPos); void SizeCheck(const void* szPos);
void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
bool IsPosValid(const void* szPos) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Validate the header data structure of a game studio MDL7 file /** Validate the header data structure of a game studio MDL7 file

View File

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

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