Compare commits

..

No commits in common. "master" and "kimkulling-patch-6" have entirely different histories.

2104 changed files with 120534 additions and 306776 deletions

2
.coveralls.yml 100644
View File

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

3
.github/FUNDING.yml vendored
View File

@ -1,2 +1,3 @@
open_collective: assimp
patreon: assimp patreon: assimp
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
open_collective: assimp

View File

@ -1,8 +1,8 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: 'Bug:' title: ''
labels: 'Bug' labels: ''
assignees: '' assignees: ''
--- ---
@ -23,10 +23,16 @@ A clear and concise description of what you expected to happen.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Platform (please complete the following information):** **Desktop (please complete the following information):**
- OS: [e.g. iOS] - OS: [e.g. iOS]
- Browser [e.g. chrome, safari] - Browser [e.g. chrome, safari]
- Version [e.g. 22] - Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@ -2,7 +2,7 @@
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: '' title: ''
labels: 'Feature-Request' labels: ''
assignees: '' assignees: ''
--- ---

View File

@ -1,25 +0,0 @@
---
name: Technical debt
about: Create a report to help us to fix and detect tech debts
title: ''
labels: 'Techdebt'
assignees: ''
---
**Describe the technical debt**
A clear and concise description of what the tech debt is about.
**Better solution**
A clear and concise description of what you would expect.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,11 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "gitsubmodule"
directory: "/" # the .gitmodules file must be placed at the top-level directory of a git working tree
schedule:
interval: "weekly"
open-pull-requests-limit: 15 # Assimp has 15 dependencies

View File

@ -6,187 +6,54 @@ on:
pull_request: pull_request:
branches: [ master ] branches: [ master ]
permissions:
contents: write # to fetch code (actions/checkout),and release
jobs: jobs:
build: job:
name: ${{ matrix.name }}-build-and-test name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++] name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux. # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include: include:
- name: windows-latest-cl.exe - name: windows-msvc
os: windows-latest os: windows-latest
cxx: cl.exe cxx: cl.exe
cc: cl.exe cc: cl.exe
- name: ubuntu-latest-clang++ - name: ubuntu-clang
os: ubuntu-latest os: ubuntu-latest
cxx: clang++ cxx: clang++
cc: clang cc: clang
- name: macos-latest-clang++ - name: macos-clang
os: macos-latest os: macos-latest
cxx: clang++ cxx: clang++
cc: clang cc: clang
- name: ubuntu-latest-g++ - name: ubuntu-gcc
os: ubuntu-latest os: ubuntu-latest
cxx: g++ cxx: g++
cc: gcc cc: gcc
steps: steps:
- name: ccache - uses: actions/checkout@v2
uses: hendrikmuhs/ccache-action@v1.2
- uses: actions/checkout@v4
with:
submodules: true
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- uses: ilammy/msvc-dev-cmd@v1 - uses: ilammy/msvc-dev-cmd@v1
- name: Set Compiler Environment - uses: lukka/set-shell-env@v1
uses: lukka/set-shell-env@v1
with: with:
CXX: ${{ matrix.cxx }} CXX: ${{ matrix.cxx }}
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
- name: Cache DX SDK
id: dxcache
if: contains(matrix.name, 'windows')
uses: actions/cache@v4
with:
path: '${{ github.workspace }}/DX_SDK'
key: ${{ runner.os }}-DX_SDK
restore-keys: |
${{ runner.os }}-DX_SDK
- name: Download DXSetup
if: contains(matrix.name, 'windows') && steps.dxcache.outputs.cache-hit != 'true'
run: |
curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
- name: Set Windows specific CMake arguments
if: contains(matrix.name, 'windows')
id: windows_extra_cmake_args
run: echo ":set-output name=args::=-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1" >> $GITHUB_OUTPUT
- name: Set Hunter specific CMake arguments
if: contains(matrix.name, 'hunter')
id: hunter_extra_cmake_args
run: echo "args=-DBUILD_SHARED_LIBS=OFF -DASSIMP_HUNTER_ENABLED=ON -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/polly/${{ matrix.toolchain }}.cmake" >> $GITHUB_OUTPUT
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v3 uses: lukka/run-cmake@v2
env:
DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}' cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release'
buildWithCMakeArgs: '--parallel 24 -v' buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/' buildDirectory: '${{ github.workspace }}/build/'
- name: Exclude certain tests in Hunter specific builds
if: contains(matrix.name, 'hunter')
id: hunter_extra_test_args
run: echo "args=--gtest_filter=-utOpenGEXImportExport.Importissue1340_EmptyCameraObject:utColladaZaeImportExport.importBlenFromFileTest" >> $GITHUB_OUTPUT
- name: test - name: test
run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }} run: cd build/bin && ./unit
shell: bash shell: bash
- uses: actions/upload-artifact@v4
if: matrix.name == 'windows-msvc'
with:
name: 'assimp-bins-${{ matrix.name }}'
path: build/bin/assimp*.exe
- uses: marvinpinto/action-automatic-releases@latest
if: contains(matrix.name, 'windows-msvc-hunter')
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "master"
prerelease: true
title: "AutoRelease"
files: |
build/bin/assimp*.exe
create-release:
needs: [build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- id: create-release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: '${{secrets.GITHUB_TOKEN}}'
with:
tag_name: '${{github.ref}}'
release_name: 'Release ${{github.ref}}'
draft: false
prerelease: true
- run: |
echo '${{steps.create-release.outputs.upload_url}}' > release_upload_url.txt
- uses: actions/upload-artifact@v4
with:
name: create-release
path: release_upload_url.txt
upload-release:
strategy:
matrix:
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include:
- name: windows-latest-cl.exe
os: windows-latest
cxx: cl.exe
cc: cl.exe
- name: ubuntu-latest-clang++
os: ubuntu-latest
cxx: clang++
cc: clang
- name: macos-latest-clang++
os: macos-latest
cxx: clang++
cc: clang
- name: ubuntu-latest-g++
os: ubuntu-latest
cxx: g++
cc: gcc
- name: ubuntu-gcc-hunter
os: ubuntu-latest
toolchain: ninja-gcc-cxx17-fpic
- name: macos-clang-hunter
os: macos-latest
toolchain: ninja-clang-cxx17-fpic
- name: windows-msvc-hunter
os: windows-latest
toolchain: ninja-vs-win64-cxx17
needs: [create-release]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: softprops/action-gh-release@v2
with:
name: create-release
- id: upload-url
run: |
echo "url=$(cat create-release/release_upload_url.txt)" >> $GITHUB_OUTPUT
- uses: actions/download-artifact@v4
with:
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
- uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: '${{secrets.GITHUB_TOKEN}}'
with:
files: |
*.zip

View File

@ -1,26 +0,0 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'assimp'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'assimp'
fuzz-seconds: 300
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

View File

@ -1,51 +0,0 @@
name: Build Windows Installer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
name: Build the Inno Setup Installer
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: lukka/get-cmake@latest
- uses: ilammy/msvc-dev-cmd@v1
- name: Cache DX SDK
id: dxcache
uses: actions/cache@v4
with:
path: '${{ github.workspace }}/DX_SDK'
key: ${{ runner.os }}-DX_SDK
restore-keys: |
${{ runner.os }}-DX_SDK
- name: Download DXSetup
run: |
curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
- name: Set Windows specific CMake arguments
id: windows_extra_cmake_args
run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1 -DASSIMP_BUILD_ZLIB=1"
- name: configure and build
uses: lukka/run-cmake@v3
env:
DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
buildWithCMakeArgs: '--parallel 24 -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: Compile .ISS to .EXE Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: packaging/windows-innosetup/script_x64.iss
options: /O+

View File

@ -6,15 +6,12 @@ on:
pull_request: pull_request:
branches: [ master ] branches: [ master ]
permissions:
contents: read # to fetch code (actions/checkout)
jobs: jobs:
job1: job1:
name: adress-sanitizer name: adress-sanitizer
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1 - uses: lukka/set-shell-env@v1
with: with:
@ -22,7 +19,7 @@ jobs:
CC: clang CC: clang
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v3 uses: lukka/run-cmake@v2
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
@ -38,7 +35,7 @@ jobs:
name: undefined-behavior-sanitizer name: undefined-behavior-sanitizer
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- 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 +43,7 @@ jobs:
CC: clang CC: clang
- name: configure and build - name: configure and build
uses: lukka/run-cmake@v3 uses: lukka/run-cmake@v2
with: with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
@ -57,13 +54,3 @@ 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

13
.gitignore vendored
View File

@ -18,14 +18,11 @@ build
*.VC.db-wal *.VC.db-wal
*.VC.opendb *.VC.opendb
*.ipch *.ipch
.vs/
out/
CMakeSettings.json
# Output # Output
bin/ bin/
lib/ lib/
x64/
# QtCreator # QtCreator
CMakeLists.txt.user CMakeLists.txt.user
@ -94,7 +91,6 @@ test/gtest/src/gtest-stamp/gtest-gitinfo.txt
test/gtest/src/gtest-stamp/gtest-gitclone-lastrun.txt test/gtest/src/gtest-stamp/gtest-gitclone-lastrun.txt
Assimp.opensdf Assimp.opensdf
contrib/zlib/CTestTestfile.cmake contrib/zlib/CTestTestfile.cmake
contrib/zlib/Debug/zlibstaticd.pdb
ipch/assimp_viewer-44bbbcd1/assimp_viewerd-ccc45335.ipch ipch/assimp_viewer-44bbbcd1/assimp_viewerd-ccc45335.ipch
bin64/assimp-vc140-mt.dll bin64/assimp-vc140-mt.dll
bin64/assimp-vc140-mtd.dll bin64/assimp-vc140-mtd.dll
@ -117,10 +113,3 @@ tools/assimp_qt_viewer/moc_glview.cpp_parameters
tools/assimp_qt_viewer/moc_mainwindow.cpp tools/assimp_qt_viewer/moc_mainwindow.cpp
tools/assimp_qt_viewer/moc_mainwindow.cpp_parameters tools/assimp_qt_viewer/moc_mainwindow.cpp_parameters
tools/assimp_qt_viewer/ui_mainwindow.h tools/assimp_qt_viewer/ui_mainwindow.h
#Generated directory
generated/*
# 3rd party cloned repos/tarballs etc
# tinyusdz repo, automatically cloned via CMake
contrib/tinyusdz/autoclone

67
.travis.sh 100755
View File

@ -0,0 +1,67 @@
#---------------------------------------------------------------------------
#Open Asset Import Library (assimp)
#---------------------------------------------------------------------------
# Copyright (c) 2006-2020, assimp team
#
# License see LICENSE file
#
function generate() {
OPTIONS="-DASSIMP_WERROR=ON"
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"
else
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
fi
if [ "$SHARED_BUILD" = "ON" ] ; then
OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=ON"
else
OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=OFF"
fi
if [ "$ENABLE_COVERALLS" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_COVERALLS=ON"
else
OPTIONS="$OPTIONS -DASSIMP_COVERALLS=OFF"
fi
if [ "$ASAN" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_ASAN=ON"
else
OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
fi
if [ "$UBSAN" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_UBSAN=ON"
fi
cmake -G "Unix Makefiles" $OPTIONS
}
# build and run unittests, if not android
if [ $ANDROID ]; then
ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
fi
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ $ANALYZE = "ON" ] ; then
if [ "$CC" = "clang" ]; then
scan-build cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_TESTS=OFF
scan-build --status-bugs make -j2
else
cppcheck --version
generate \
&& cppcheck --error-exitcode=1 -j2 -Iinclude -Icode code 2> cppcheck.txt
if [ -s cppcheck.txt ]; then
cat cppcheck.txt
exit 1
fi
fi
else
generate \
&& make -j4 \
&& sudo make install \
&& sudo ldconfig \
&& (cd test/unit; ../../bin/unit)
fi
fi

78
.travis.yml 100644
View File

@ -0,0 +1,78 @@
sudo: required
language: cpp
cache: ccache
before_install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake cppcheck && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
- 'if [ "$TRAVIS_OS_NAME" = "osx" ]; then
if brew ls --versions cmake > /dev/null; then
echo cmake already installed.;
else
brew install cmake;
fi;
brew install python3;
brew install homebrew/x11/freeglut;
fi'
- echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
# install latest LCOV (1.9 was failing)
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
os:
- linux
compiler:
- gcc
- clang
env:
global:
- secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
- PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
git:
depth: 1
matrix:
include:
- os: linux
compiler: clang
env: ASAN=ON
- os: linux
compiler: clang
env: UBSAN=ON
- os: linux
compiler: clang
env: SHARED_BUILD=ON
- os: linux
compiler: gcc
env: ANALYZE=ON
- os: linux
compiler: gcc
env: ENABLE_COVERALLS=ON
- os: linux
compiler: gcc
env: SHARED_BUILD=ON
install:
- if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
before_script:
cmake . -DASSIMP_ENABLE_BOOST_WORKAROUND=YES
script:
- export COVERALLS_SERVICE_NAME=travis-ci
- export COVERALLS_REPO_TOKEN=abc12345
- . ./.travis.sh
after_success:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
addons:
coverity_scan:
project:
name: "assimp/assimp"
notification_email: kim.kulling@googlemail.com
build_command_prepend: "cmake ./"
build_command: "make -j4"
branch_pattern: coverity_scan

View File

@ -0,0 +1,3 @@
set(ASSIMP_INCLUDE_DIRS
"@PROJECT_SOURCE_DIR@"
"@PROJECT_BINARY_DIR@")

View File

@ -0,0 +1,11 @@
set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View File

@ -10,15 +10,16 @@
:: Also see: https://github.com/assimp/assimp/pull/2646 :: Also see: https://github.com/assimp/assimp/pull/2646
SET SOURCE_DIR=. SET SOURCE_DIR=.
SET GENERATOR=Visual Studio 16 2019
SET BINARIES_DIR="./build/Win32" :: For generators see "cmake --help"
cmake . -G "%GENERATOR%" -A Win32 -S %SOURCE_DIR% -B %BINARIES_DIR% SET GENERATOR=Visual Studio 15 2017
cmake --build %BINARIES_DIR% --config debug
SET BINARIES_DIR="./BINARIES/Win32"
cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config release cmake --build %BINARIES_DIR% --config release
SET BINARIES_DIR="./build/x64" SET BINARIES_DIR="./BINARIES/x64"
cmake . -G "%GENERATOR%" -A x64 -S %SOURCE_DIR% -B %BINARIES_DIR% cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug cmake --build %BINARIES_DIR% --config debug
cmake --build %BINARIES_DIR% --config release cmake --build %BINARIES_DIR% --config release

View File

@ -1,33 +1,20 @@
# Build / Install Instructions # Build Instructions
## Install on all platforms using vcpkg ## Build on all platforms using vcpkg
You can download and install assimp using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: You can download and install assimp using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
```bash ```bash
git clone https://github.com/Microsoft/vcpkg.git git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg cd vcpkg
./bootstrap-vcpkg.sh ./bootstrap-vcpkg.sh
./vcpkg integrate install ./vcpkg integrate install
./vcpkg install assimp vcpkg install assimp
``` ```
The assimp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. The assimp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
## Install on Ubuntu
You can install the Asset-Importer-Lib via apt:
```
sudo apt-get update
sudo apt-get install libassimp-dev
```
## Install pyassimp
You need to have pip installed:
```
pip install pyassimp
```
## Manual build instructions ## Manual build instructions
### Install CMake ### Install CMake
Asset-Importer-Lib can be built for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via
```bash ```bash
sudo apt-get install cmake sudo apt-get install cmake
``` ```
@ -37,22 +24,15 @@ Make sure you have a working git-installation. Open a command prompt and clone t
```bash ```bash
git clone https://github.com/assimp/assimp.git git clone https://github.com/assimp/assimp.git
``` ```
### Build from source:
```bash
cd assimp
cmake CMakeLists.txt
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
First, you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/ First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/
To generate the build environment for your IDE open a command prompt, navigate to your repo and type: To generate the build environment for your IDE open a command prompt, navigate to your repo and type:
```bash ```bash
cmake CMakeLists.txt cmake CMakeLists.txt
``` ```
This will generate the project files for the visual studio. All dependencies used to build Asset-Importer-Lib shall be part of the repo. If you want to use you own zlib installation this is possible as well. Check the options for it. This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it.
### Build instructions for Windows with UWP ### Build instructions for Windows with UWP
See <https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app> See <https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app>
@ -64,9 +44,9 @@ Open a terminal and got to your repository. You can generate the makefiles and b
cmake CMakeLists.txt cmake CMakeLists.txt
make -j4 make -j4
``` ```
The option -j describes the number of parallel processes for the build. In this case make will try to use 4 cores for the build. The option -j descripes the number of parallel processes for the build. In this case make will try to use 4 cores for the build.
If you want to use an IDE for linux you can try QTCreator for instance. If you want to use a IDE for linux you can try QTCreator for instance.
### Build instructions for MinGW ### Build instructions for MinGW
Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag
@ -86,28 +66,23 @@ Besides the toolchain, compilation should be the same as for Linux / Unix.
### CMake build options ### CMake build options
The cmake-build-environment provides options to configure the build. The following options can be used: The cmake-build-environment provides options to configure the build. The following options can be used:
- **ASSIMP_HUNTER_ENABLED (default OFF)**: Enable Hunter package manager support. - **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib.
- **BUILD_SHARED_LIBS (default ON)**: Generation of shared libs (dll for windows, so for Linux). Set this to OFF to get a static lib. - **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle
- **ASSIMP_BUILD_FRAMEWORK (default OFF, MacOnly)**: Build package as Mac OS X Framework bundle. - **ASSIMP_DOUBLE_PRECISION( default OFF )**: All data will be stored as double values.
- **ASSIMP_DOUBLE_PRECISION (default OFF)**: All data will be stored as double values. - **ASSIMP_OPT_BUILD_PACKAGES ( default OFF)**: Set to ON to generate CPack configuration files and packaging targets
- **ASSIMP_OPT_BUILD_PACKAGES (default OFF)**: Set to ON to generate CPack configuration files and packaging targets. - **ASSIMP_ANDROID_JNIIOSYSTEM ( default OFF )**: Android JNI IOSystem support is active
- **ASSIMP_ANDROID_JNIIOSYSTEM (default OFF)**: Android JNI IOSystem support is active. - **ASSIMP_NO_EXPORT ( default OFF )**: Disable Assimp's export functionality
- **ASSIMP_NO_EXPORT (default OFF)**: Disable Assimp's export functionality. - **ASSIMP_BUILD_ZLIB ( default OFF )**: Build your own zlib
- **ASSIMP_BUILD_ZLIB (default OFF)**: Build our own zlib. - **ASSIMP_BUILD_ASSIMP_TOOLS ( default ON )**: If the supplementary tools for Assimp are built in addition to the library.
- **ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all exporters enabled. - **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
- **ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all importers enabled. - **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
- **ASSIMP_BUILD_ASSIMP_TOOLS (default OFF)**: If the supplementary tools for Assimp are built in addition to the library. - **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
- **ASSIMP_BUILD_SAMPLES (default OFF)**: If the official samples are built as well (needs Glut). - **ASSIMP_ERROR_MAX( default OFF)**: Enable all warnings.
- **ASSIMP_BUILD_TESTS (default ON)**: If the test suite for Assimp is built in addition to the library. - **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
- **ASSIMP_COVERALLS (default OFF)**: Enable this to measure test coverage. - **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
- **ASSIMP_INSTALL (default ON)**: Install Assimp library. Disable this if you want to use Assimp as a submodule. - **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.
- **ASSIMP_WARNINGS_AS_ERRORS (default ON)**: Treat all warnings as errors. - **SYSTEM_IRRXML ( default OFF )**: Use system installed Irrlicht/IrrXML library.
- **ASSIMP_ASAN (default OFF)**: Enable AddressSanitizer. - **BUILD_DOCS ( default OFF )**: Build documentation using Doxygen.
- **ASSIMP_UBSAN (default OFF)**: Enable Undefined Behavior sanitizer. - **INJECT_DEBUG_POSTFIX( default ON )**: Inject debug postfix in .a/.so lib names
- **ASSIMP_BUILD_DOCS (default OFF)**: Build documentation using Doxygen. OBSOLETE, see https://github.com/assimp/assimp-docs - **IGNORE_GIT_HASH ( default OFF )**: Don't call git to get the hash.
- **ASSIMP_INJECT_DEBUG_POSTFIX (default ON)**: Inject debug postfix in .a/.so/.lib/.dll lib names - **ASSIMP_INSTALL_PDB ( default ON )**: Install MSVC debug files.
- **ASSIMP_IGNORE_GIT_HASH (default OFF)**: Don't call git to get the hash.
- **ASSIMP_INSTALL_PDB (default ON)**: Install MSVC debug files.
- **USE_STATIC_CRT (default OFF)**: Link against the static MSVC runtime libraries.
- **ASSIMP_BUILD_DRACO (default OFF)**: Build Draco libraries. Primarily for glTF.
- **ASSIMP_BUILD_ASSIMP_VIEW (default ON, if DirectX found, OFF otherwise)**: Build Assimp view tool (requires DirectX).

View File

@ -1,6 +1,6 @@
# Open Asset Import Library (assimp) # Open Asset Import Library (assimp)
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# Copyright (c) 2006-2024, assimp team # Copyright (c) 2006-2020, assimp team
# #
# All rights reserved. # All rights reserved.
# #
@ -34,44 +34,24 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW)
SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)
CMAKE_MINIMUM_REQUIRED( VERSION 3.22 ) CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
# Experimental USD importer: disabled, need to opt-in
# Note: assimp github PR automatic checks will fail the PR due to compiler warnings in
# the external, 3rd party tinyusdz code which isn't technically part of the PR since it's
# auto-cloned during build; so MUST disable the feature or the PR will be rejected
option(ASSIMP_BUILD_USD_IMPORTER "Enable USD file import" off)
option(ASSIMP_BUILD_USD_VERBOSE_LOGS "Enable verbose USD import debug logging" off)
option(ASSIMP_BUILD_USE_CCACHE "Use ccache to speed up compilation." on)
if(ASSIMP_BUILD_USE_CCACHE)
find_program(CCACHE_PATH ccache)
if (CCACHE_PATH)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
endif()
endif()
# Disabled importers: m3d for 5.1 or later
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_IMPORTER)
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_EXPORTER)
# Toggles the use of the hunter package manager # Toggles the use of the hunter package manager
option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) 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/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.25.5.tar.gz" URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
SHA1 "a20151e4c0740ee7d0f9994476856d813cdead29" SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
ENDIF() ENDIF()
PROJECT(Assimp VERSION 5.4.3) PROJECT( Assimp VERSION 5.0.1 )
# All supported options ############################################### # All supported options ###############################################
@ -79,6 +59,7 @@ OPTION( BUILD_SHARED_LIBS
"Build package with shared libraries." "Build package with shared libraries."
ON ON
) )
OPTION( ASSIMP_BUILD_FRAMEWORK OPTION( ASSIMP_BUILD_FRAMEWORK
"Build package as Mac OS X Framework bundle." "Build package as Mac OS X Framework bundle."
OFF OFF
@ -99,9 +80,13 @@ 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 ON
) )
OPTION ( ASSIMP_BUILD_SAMPLES OPTION ( ASSIMP_BUILD_SAMPLES
"If the official samples are built as well (needs Glut)." "If the official samples are built as well (needs Glut)."
@ -119,9 +104,9 @@ OPTION( ASSIMP_INSTALL
"Disable this if you want to use assimp as a submodule." "Disable this if you want to use assimp as a submodule."
ON ON
) )
OPTION ( ASSIMP_WARNINGS_AS_ERRORS OPTION ( ASSIMP_ERROR_MAX
"Treat all warnings as errors." "Enable all warnings."
ON OFF
) )
OPTION ( ASSIMP_ASAN OPTION ( ASSIMP_ASAN
"Enable AddressSanitizer." "Enable AddressSanitizer."
@ -131,6 +116,10 @@ OPTION ( ASSIMP_UBSAN
"Enable Undefined Behavior sanitizer." "Enable Undefined Behavior sanitizer."
OFF OFF
) )
OPTION ( ASSIMP_SYSTEM_IRRXML
"Use system installed Irrlicht/IrrXML library."
OFF
)
OPTION ( ASSIMP_BUILD_DOCS OPTION ( ASSIMP_BUILD_DOCS
"Build documentation using Doxygen." "Build documentation using Doxygen."
OFF OFF
@ -145,46 +134,10 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF OFF
) )
IF (WIN32) IF ( WIN32 )
OPTION( ASSIMP_BUILD_ZLIB OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
"Build your zlib" "If the Assimp view tool is built. (requires DirectX)"
ON OFF )
)
ELSE()
OPTION( ASSIMP_BUILD_ZLIB
"Build your zlib"
OFF
)
ENDIF()
IF (WIN32)
# Use a subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
IF(MSVC)
OPTION( ASSIMP_INSTALL_PDB
"Create MSVC debug symbol files and add to Install target."
ON )
IF(NOT (MSVC_VERSION LESS 1900))
# Multibyte character set has been deprecated since at least MSVC2015 (possibly earlier)
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
ENDIF()
# Link statically against c/c++ lib to avoid missing redistributable such as
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
# a choice to opt for the shared runtime if they want.
option(USE_STATIC_CRT "Link against the static runtime libraries." OFF)
# The CMAKE_CXX_FLAGS vars can be overridden by some Visual Studio generators, so we use an alternative
# global method here:
if (${USE_STATIC_CRT})
add_compile_options(
$<$<CONFIG:>:/MT>
$<$<CONFIG:Debug>:/MTd>
$<$<CONFIG:Release>:/MT>
)
endif()
ENDIF()
ENDIF() ENDIF()
IF (IOS AND NOT ASSIMP_HUNTER_ENABLED) IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
@ -194,6 +147,21 @@ IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
ADD_DEFINITIONS(-DENABLE_BITCODE) ADD_DEFINITIONS(-DENABLE_BITCODE)
ENDIF () ENDIF ()
# Use subset of Windows.h
if (WIN32)
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
endif()
IF(MSVC)
OPTION( ASSIMP_INSTALL_PDB
"Install MSVC debug files."
ON
)
IF(NOT (MSVC_VERSION LESS 1900))
# Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
ENDIF()
ENDIF()
IF (ASSIMP_BUILD_FRAMEWORK) IF (ASSIMP_BUILD_FRAMEWORK)
SET (BUILD_SHARED_LIBS ON) SET (BUILD_SHARED_LIBS ON)
@ -203,7 +171,6 @@ ENDIF()
IF(NOT BUILD_SHARED_LIBS) IF(NOT BUILD_SHARED_LIBS)
MESSAGE(STATUS "Shared libraries disabled") MESSAGE(STATUS "Shared libraries disabled")
SET(LINK_SEARCH_START_STATIC TRUE) SET(LINK_SEARCH_START_STATIC TRUE)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES})
ELSE() ELSE()
MESSAGE(STATUS "Shared libraries enabled") MESSAGE(STATUS "Shared libraries enabled")
ENDIF() ENDIF()
@ -216,9 +183,10 @@ 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" )
set(CMAKE_CXX_STANDARD 17) if(NOT ASSIMP_HUNTER_ENABLED)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # Enable C++11 support globally
set(CMAKE_C_STANDARD 99) set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
endif()
IF(NOT ASSIMP_IGNORE_GIT_HASH) IF(NOT ASSIMP_IGNORE_GIT_HASH)
# Get the current working branch # Get the current working branch
@ -248,6 +216,16 @@ IF(ASSIMP_DOUBLE_PRECISION)
ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
ENDIF() ENDIF()
CONFIGURE_FILE(
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
${CMAKE_CURRENT_BINARY_DIR}/revision.h
)
CONFIGURE_FILE(
${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h
)
INCLUDE_DIRECTORIES( BEFORE INCLUDE_DIRECTORIES( BEFORE
./ ./
code/ code/
@ -265,80 +243,46 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
IF( UNIX ) 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
IF(NOT ${OPERATING_SYSTEM} MATCHES "Android")
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit Linux
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF()
ENDIF()
ENDIF() ENDIF()
# Grouped compiler settings ######################################## # Grouped compiler settings ########################################
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU) IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_STANDARD 11)
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" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSE()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++) SET(LIBSTDC++_LIBRARIES -lstdc++)
ENDIF()
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 ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX )
ADD_COMPILE_OPTIONS(/bigobj)
ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj)
ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
# supress warning for double to float conversion if Double precision is activated
ADD_COMPILE_OPTIONS(/wd4244)
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
# Allow user to disable PDBs ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
if(ASSIMP_INSTALL_PDB)
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
elseif((GENERATOR_IS_MULTI_CONFIG) OR (CMAKE_BUILD_TYPE MATCHES Release))
message("-- MSVC PDB generation disabled. Release binary will not be debuggable.")
endif()
# Source code is encoded in UTF-8
ADD_COMPILE_OPTIONS(/source-charset:utf-8)
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_STANDARD 11)
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}" )
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
ELSEIF( MINGW ) ELSEIF( CMAKE_COMPILER_IS_MINGW )
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.") message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.")
ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3) ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
message(WARNING "MinGW is old, if you experience errors, update MinGW.") message(WARNING "MinGW is old, if you experience errors, update MinGW.")
ENDIF() ENDIF()
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-std=gnu++17 ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
ENDIF() ENDIF()
IF (CMAKE_BUILD_TYPE STREQUAL "Debug") SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wno-dangling-reference -Wall -Wno-long-long -Wa,-mbig-obj -g ${CMAKE_CXX_FLAGS}")
ELSE()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wno-dangling-reference -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
ENDIF()
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF() ENDIF()
IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED) IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
@ -348,63 +292,55 @@ IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
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")
ENDIF() ENDIF()
IF (ASSIMP_ERROR_MAX)
MESSAGE(STATUS "Turning on all warnings")
IF (MSVC)
ADD_COMPILE_OPTIONS(/W4) # NB: there is a /Wall option, pedantic mode
ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
ENDIF()
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 -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 -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)
INCLUDE (PrecompiledHeader) INCLUDE (PrecompiledHeader)
# Set Assimp project output directory variables. # If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR),
# Will respect top-level CMAKE_*_OUTPUT_DIRECTORY variables if any are set. # write the library/executable files to the respective directories in the
IF(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) # source tree. During an out-of-source build, however, do not litter this
SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files") # directory, since that is probably what the user wanted to avoid.
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
ELSE() ELSE()
SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files") SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
ENDIF() SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
IF(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY) ENDIF ()
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files")
ELSE()
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
ENDIF()
IF(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for library output files")
ELSE()
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
ENDIF()
# Macro used to set the output directories of a target to the
# respective Assimp output directories.
MACRO(TARGET_USE_COMMON_OUTPUT_DIRECTORY target)
set_target_properties(${target} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${ASSIMP_RUNTIME_OUTPUT_DIRECTORY}
LIBRARY_OUTPUT_DIRECTORY ${ASSIMP_LIBRARY_OUTPUT_DIRECTORY}
ARCHIVE_OUTPUT_DIRECTORY ${ASSIMP_ARCHIVE_OUTPUT_DIRECTORY}
)
ENDMACRO()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
@ -415,20 +351,65 @@ ELSE()
ENDIF() ENDIF()
# Only generate this target if no higher-level project already has # Only generate this target if no higher-level project already has
IF (NOT TARGET uninstall AND ASSIMP_INSTALL) IF (NOT TARGET uninstall)
# add make uninstall capability # add make uninstall capability
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF() ENDIF()
IF( UNIX ) IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(INCLUDE_INSTALL_DIR "include")
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
# Configuration
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(NAMESPACE "${PROJECT_NAME}::")
# Include module with fuction 'write_basic_package_version_file'
include(CMakePackageConfigHelpers)
# Note: PROJECT_VERSION is used as a VERSION
write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
# Use variables:
# * TARGETS_EXPORT_NAME
# * PROJECT_NAME
configure_package_config_file(
"cmake/assimp-hunter-config.cmake.in"
"${PROJECT_CONFIG}"
INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
)
install(
FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
DESTINATION "${CONFIG_INSTALL_DIR}"
)
install(
EXPORT "${TARGETS_EXPORT_NAME}"
NAMESPACE "${NAMESPACE}"
DESTINATION "${CONFIG_INSTALL_DIR}"
)
ELSE()
# cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR}) SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
ELSE() ELSE()
# Cache these to allow the user to override them on non-Unix platforms # Cache these to allow the user to override them on non-Unix platforms
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
"Path the built library files are installed to." ) "Path the built library files are installed to." )
@ -440,60 +421,40 @@ ELSE()
SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR}) SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}) SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR}) SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
ENDIF()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
IF (is_multi_config)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake")
ELSE()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
ENDIF()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
#we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
INSTALL(FILES
"${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
${PACKAGE_TARGETS_FILE}
DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
ENDIF() ENDIF()
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake-modules/assimp-hunter-config.cmake.in")
set(NAMESPACE "${PROJECT_NAME}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
ELSE()
set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake-modules/assimp-plain-config.cmake.in")
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE)
set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets")
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}Config.cmake")
ENDIF()
set(INCLUDE_INSTALL_DIR "include")
# Include module with fuction 'write_basic_package_version_file'
include(CMakePackageConfigHelpers)
# Note: PROJECT_VERSION is used as a VERSION
write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
configure_package_config_file(
${CMAKE_CONFIG_TEMPLATE_FILE}
"${PROJECT_CONFIG}"
INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
)
if(ASSIMP_INSTALL)
install(
FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
DESTINATION "${CONFIG_INSTALL_DIR}"
COMPONENT ${LIBASSIMP-DEV_COMPONENT}
)
install(
EXPORT "${TARGETS_EXPORT_NAME}"
NAMESPACE "${NAMESPACE}"
DESTINATION "${CONFIG_INSTALL_DIR}"
COMPONENT ${LIBASSIMP-DEV_COMPONENT}
)
endif()
IF( ASSIMP_BUILD_DOCS ) IF( ASSIMP_BUILD_DOCS )
ADD_SUBDIRECTORY(doc) ADD_SUBDIRECTORY(doc)
ENDIF() ENDIF()
# Look for system installed irrXML
IF ( ASSIMP_SYSTEM_IRRXML )
FIND_PACKAGE( IrrXML REQUIRED )
ENDIF()
# Search for external dependencies, and build them from source if not found # Search for external dependencies, and build them from source if not found
# Search for zlib # Search for zlib
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
@ -505,21 +466,11 @@ IF(ASSIMP_HUNTER_ENABLED)
set(ZLIB_LIBRARIES ZLIB::zlib) set(ZLIB_LIBRARIES ZLIB::zlib)
set(ASSIMP_BUILD_MINIZIP TRUE) set(ASSIMP_BUILD_MINIZIP TRUE)
ELSE() ELSE()
# If the zlib is already found outside, add an export in case assimpTargets can't find it.
IF( ZLIB_FOUND AND ASSIMP_INSTALL)
INSTALL( TARGETS zlib zlibstatic
EXPORT "${TARGETS_EXPORT_NAME}")
ENDIF()
IF ( NOT ASSIMP_BUILD_ZLIB ) IF ( NOT ASSIMP_BUILD_ZLIB )
FIND_PACKAGE(ZLIB) FIND_PACKAGE(ZLIB)
ENDIF() ENDIF()
IF ( NOT ZLIB_FOUND AND NOT ASSIMP_BUILD_ZLIB ) IF( NOT ZLIB_FOUND )
message( FATAL_ERROR
"Build configured with -DASSIMP_BUILD_ZLIB=OFF but unable to find zlib"
)
ELSEIF( NOT ZLIB_FOUND )
MESSAGE(STATUS "compiling zlib from sources") MESSAGE(STATUS "compiling zlib from sources")
INCLUDE(CheckIncludeFile) INCLUDE(CheckIncludeFile)
INCLUDE(CheckTypeSize) INCLUDE(CheckTypeSize)
@ -584,19 +535,15 @@ ENDIF()
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL
"Build the C4D importer, which relies on the non-free Cineware SDK." "Build the C4D importer, which relies on the non-free Melange SDK."
) )
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/includes") IF ( MSVC )
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
IF (WIN32)
# pick the correct prebuilt library # pick the correct prebuilt library
IF(MSVC143) IF(MSVC15)
SET(C4D_LIB_POSTFIX "_2022")
ELSEIF(MSV142)
SET(C4D_LIB_POSTFIX "_2019")
ELSEIF(MSVC15)
SET(C4D_LIB_POSTFIX "_2017") SET(C4D_LIB_POSTFIX "_2017")
ELSEIF(MSVC14) ELSEIF(MSVC14)
SET(C4D_LIB_POSTFIX "_2015") SET(C4D_LIB_POSTFIX "_2015")
@ -608,162 +555,50 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
SET(C4D_LIB_POSTFIX "_2010") SET(C4D_LIB_POSTFIX "_2010")
ELSE() ELSE()
MESSAGE( FATAL_ERROR MESSAGE( FATAL_ERROR
"C4D for Windows is currently only supported with MSVC 10, 11, 12, 14, 14.2, 14.3" "C4D is currently only supported with MSVC 10, 11, 12, 14"
) )
ENDIF() ENDIF()
SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/libraries/win") SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/libraries/win")
SET(C4D_DEBUG_LIBRARIES SET(C4D_DEBUG_LIBRARIES
"${C4D_LIB_BASE_PATH}/cinewarelib${C4D_LIB_POSTFIX}/cinewarelib_debug.lib" "${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_debug.lib"
"${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_debug.lib" "${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_debug.lib"
) )
SET(C4D_RELEASE_LIBRARIES SET(C4D_RELEASE_LIBRARIES
"${C4D_LIB_BASE_PATH}/cinewarelib${C4D_LIB_POSTFIX}/cinewarelib_release.lib" "${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_release.lib"
"${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_release.lib" "${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_release.lib"
) )
# winsock and winmm are necessary (and undocumented) dependencies of Cineware SDK because # winsock and winmm are necessary dependencies of melange (this is undocumented, but true.)
# it can be used to communicate with a running Cinema 4D instance
SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib) SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib)
ELSEIF (APPLE)
SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/libraries/osx")
SET(C4D_DEBUG_LIBRARIES
"${C4D_LIB_BASE_PATH}/debug/libcinewarelib.a"
"${C4D_LIB_BASE_PATH}/debug/libjpeglib.a"
)
SET(C4D_RELEASE_LIBRARIES
"${C4D_LIB_BASE_PATH}/release/libcinewarelib.a"
"${C4D_LIB_BASE_PATH}/release/libjpeglib.a"
)
ELSE () ELSE ()
MESSAGE( FATAL_ERROR MESSAGE( FATAL_ERROR
"C4D is currently only available on Windows and macOS with Cineware SDK installed in contrib/Cineware" "C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
) )
ENDIF () ENDIF ()
ELSE () ELSE ()
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
ENDIF () ENDIF ()
if(ASSIMP_BUILD_DRACO_STATIC) IF(NOT ASSIMP_HUNTER_ENABLED)
set(ASSIMP_BUILD_DRACO ON) ADD_SUBDIRECTORY(contrib)
endif()
# Draco requires cmake 3.12
IF (DEFINED CMAKE_VERSION AND "${CMAKE_VERSION}" VERSION_LESS "3.12")
message(NOTICE "draco requires cmake 3.12 or newer, cmake is ${CMAKE_VERSION} . Draco is disabled")
SET ( ASSIMP_BUILD_DRACO OFF CACHE BOOL "Disabled: Draco requires newer cmake" FORCE )
ELSE()
OPTION ( ASSIMP_BUILD_DRACO "If the Draco libraries are to be built. Primarily for glTF" OFF )
IF ( ASSIMP_BUILD_DRACO )
# Primarily for glTF v2
# Enable Draco glTF feature set
set(DRACO_GLTF_BITSTREAM ON CACHE BOOL "" FORCE)
# Disable unnecessary or omitted components
set(DRACO_JS_GLUE OFF CACHE BOOL "" FORCE)
set(DRACO_WASM OFF CACHE BOOL "" FORCE)
set(DRACO_MAYA_PLUGIN OFF CACHE BOOL "" FORCE)
set(DRACO_UNITY_PLUGIN OFF CACHE BOOL "" FORCE)
set(DRACO_TESTS OFF CACHE BOOL "" FORCE)
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(draco)
find_package(draco CONFIG REQUIRED)
set(draco_LIBRARIES draco::draco)
ELSE()
# Draco 1.4.1 has many warnings and will not build with /WX or -Werror
# See https://github.com/google/draco/issues/672
# and https://github.com/google/draco/issues/673
IF(MSVC)
set(DRACO_CXX_FLAGS "/W0")
ELSE()
list(APPEND DRACO_CXX_FLAGS
"-Wno-bool-compare"
"-Wno-comment"
"-Wno-maybe-uninitialized"
"-Wno-sign-compare"
"-Wno-unused-local-typedefs"
)
if(NOT ASSIMP_BUILD_DRACO_STATIC)
# Draco 1.4.1 does not explicitly export any symbols under GCC/clang
list(APPEND DRACO_CXX_FLAGS
"-fvisibility=default"
)
endif()
ENDIF()
# Don't build or install all of Draco by default
ADD_SUBDIRECTORY( "contrib/draco" EXCLUDE_FROM_ALL )
if(ASSIMP_BUILD_DRACO_STATIC)
set_property(DIRECTORY "contrib/draco" PROPERTY BUILD_SHARED_LIBS OFF)
endif()
if(MSVC OR WIN32)
set(draco_LIBRARIES "draco")
else()
if(ASSIMP_BUILD_DRACO_STATIC)
set(draco_LIBRARIES "draco_static")
else()
set(draco_LIBRARIES "draco_shared")
endif()
endif()
# Don't build the draco command-line tools by default
set_target_properties(draco_encoder draco_decoder PROPERTIES
EXCLUDE_FROM_ALL TRUE
EXCLUDE_FROM_DEFAULT_BUILD TRUE
)
# Do build the draco shared library
set_target_properties(${draco_LIBRARIES} PROPERTIES
EXCLUDE_FROM_ALL FALSE
EXCLUDE_FROM_DEFAULT_BUILD FALSE
)
TARGET_USE_COMMON_OUTPUT_DIRECTORY(${draco_LIBRARIES})
TARGET_USE_COMMON_OUTPUT_DIRECTORY(draco_encoder)
TARGET_USE_COMMON_OUTPUT_DIRECTORY(draco_decoder)
set(draco_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/draco/src")
# This is probably wrong
if (ASSIMP_INSTALL)
INSTALL( TARGETS ${draco_LIBRARIES}
EXPORT "${TARGETS_EXPORT_NAME}"
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
COMPONENT ${LIBASSIMP_COMPONENT}
INCLUDES DESTINATION include
)
endif()
ENDIF()
ENDIF()
ENDIF() ENDIF()
# Main assimp code
ADD_SUBDIRECTORY( code/ ) ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# The viewer for windows only # The viewer for windows only
IF (WIN32) IF ( WIN32 )
FIND_PACKAGE(DirectX) OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
IF ( ASSIMP_BUILD_ASSIMP_VIEW ) IF ( ASSIMP_BUILD_ASSIMP_VIEW )
ADD_SUBDIRECTORY( tools/assimp_view/ ) ADD_SUBDIRECTORY( tools/assimp_view/ )
ENDIF () ENDIF ()
ELSE()
MESSAGE("Building Assimp Viewer only supported on Windows.")
ENDIF () ENDIF ()
# The command line tool # The command line tool
ADD_SUBDIRECTORY( tools/assimp_cmd/ ) ADD_SUBDIRECTORY( tools/assimp_cmd/ )
ENDIF () ENDIF ()
IF ( ASSIMP_BUILD_SAMPLES ) IF ( ASSIMP_BUILD_SAMPLES)
SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples ) SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples )
SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode ) SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode )
IF ( WIN32 ) IF ( WIN32 )
@ -777,22 +612,12 @@ IF ( ASSIMP_BUILD_TESTS )
ADD_SUBDIRECTORY( test/ ) ADD_SUBDIRECTORY( test/ )
ENDIF () ENDIF ()
# Generate a pkg-config .pc, revision.h, and config.h for the Assimp library. # Generate a pkg-config .pc for the Assimp library.
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY ) CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
IF ( ASSIMP_INSTALL ) IF ( ASSIMP_INSTALL )
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT}) INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
ENDIF() ENDIF()
CONFIGURE_FILE(
${CMAKE_CURRENT_LIST_DIR}/include/assimp/revision.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/assimp/revision.h
)
CONFIGURE_FILE(
${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h
)
IF ( ASSIMP_INSTALL ) IF ( ASSIMP_INSTALL )
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
# Packing information # Packing information
@ -826,7 +651,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)
@ -854,8 +679,7 @@ if(WIN32)
ENDIF() ENDIF()
IF(MSVC_TOOLSET_VERSION) IF(MSVC_TOOLSET_VERSION)
SET(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
SET(ASSIMP_MSVC_VERSION ${MSVC_PREFIX})
ELSE() ELSE()
IF(MSVC12) IF(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120") SET(ASSIMP_MSVC_VERSION "vc120")
@ -863,10 +687,6 @@ if(WIN32)
SET(ASSIMP_MSVC_VERSION "vc140") SET(ASSIMP_MSVC_VERSION "vc140")
ELSEIF(MSVC15) ELSEIF(MSVC15)
SET(ASSIMP_MSVC_VERSION "vc141") SET(ASSIMP_MSVC_VERSION "vc141")
ELSEIF(MSV142)
SET(ASSIMP_MSVC_VERSION "vc142")
ELSEIF(MSVC143)
SET(ASSIMP_MSVC_VERSION "vc143")
ENDIF() ENDIF()
ENDIF() ENDIF()

View File

@ -1,128 +0,0 @@
# 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,22 +0,0 @@
FROM ubuntu:22.04
RUN apt-get update && apt-get install --no-install-recommends -y ninja-build \
git cmake build-essential software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
WORKDIR /opt
RUN apt install zlib1g-dev
# Build Assimp
RUN git clone https://github.com/assimp/assimp.git /opt/assimp
WORKDIR /opt/assimp
RUN git checkout master \
&& mkdir build && cd build && \
cmake -G 'Ninja' \
-DCMAKE_BUILD_TYPE=Release \
-DASSIMP_BUILD_ASSIMP_TOOLS=ON \
.. && \
ninja -j4 && ninja install

37
INSTALL
View File

@ -8,10 +8,43 @@ Getting the documentation
------------------------------ ------------------------------
A regularly-updated copy is available at A regularly-updated copy is available at
https://assimp-docs.readthedocs.io/en/latest/ http://assimp.sourceforge.net/lib_html/index.html
A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
To build the doxygen documentation on your own, follow these steps:
a) download & install latest doxygen
b) make sure doxygen is in the executable search path
c) navigate to ./doc
d) and run 'doxygen'
Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
and configure the path to it in the DOXYFILE first.
------------------------------ ------------------------------
Building Assimp Building Assimp
------------------------------ ------------------------------
Just check the build-instructions which you can find here: https://github.com/assimp/assimp/blob/master/Build.md More detailed build instructions can be found in the documentation,
this section is just for the inpatient among you.
CMake is the preferred build system for Assimp. The minimum required version
is 2.6. If you don't have it yet, downloads for CMake can be found on
http://www.cmake.org/.
For Unix:
1. mkdir build && cd build
2. cmake .. -G 'Unix Makefiles'
3. make -j4
For Windows:
1. Open a command prompt
2. mkdir build
3. cd build
4. cmake ..
5. cmake --build .
For iOS:
Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS

View File

@ -1,6 +1,6 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2020, 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,

1
README 100644
View File

@ -0,0 +1 @@
See Readme.md

View File

@ -1,82 +1,85 @@
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)
[![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) [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
<a href="https://scan.coverity.com/projects/5607">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5607/badge.svg"/>
</a>
[![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") [![Codacy Badge](https://api.codacy.com/project/badge/Grade/5be56faac64f46fc941ac890fb4febef)](https://www.codacy.com/app/kimkulling/assimp?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade)
[![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.
### Documentation ### [Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
Read [our latest documentation](https://assimp-docs.readthedocs.io/en/latest/).
### Pre-built binaries ### 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.
Download binaries from [our Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).
### Test data ### 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).
Clone [our model database](https://github.com/assimp/assimp-mdb).
### Communities ### Please check our Wiki as well: https://github.com/assimp/assimp/wiki
- Ask questions at [the Assimp Discussion Board](https://github.com/assimp/assimp/discussions).
- Find us on [https://discord.gg/s9KJfaem](https://discord.gg/kKazXMXDy2) If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
- Ask [the Assimp community on Reddit](https://www.reddit.com/r/Assimp/).
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
- Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
#### Supported file formats #### #### Supported file formats ####
See [the complete list of supported formats](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 ###
Start by reading [our build instructions](https://github.com/assimp/assimp/blob/master/Build.md). 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 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.
### Ports ### ### Ports ###
* [Android](port/AndroidJNI/README.md) * [Android](port/AndroidJNI/README.md)
* [Python](port/PyAssimp/README.md) * [Python](port/PyAssimp/README.md)
* [.NET](https://bitbucket.org/Starnick/assimpnet/src/master/) * [.NET](https://github.com/assimp/assimp-net)
* [Pascal](port/AssimpPascal/Readme.md) * [Pascal](port/AssimpPascal/Readme.md)
* [Javascript (Alpha)](https://github.com/makc/assimp2json) * [Javascript (Alpha)](https://github.com/makc/assimp2json)
* [Javascript/Node.js Interface](https://github.com/kovacsv/assimpjs) * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
* [Unity 3d Plugin](https://ricardoreis.net/trilib-2/)
* [Unreal Engine Plugin](https://github.com/irajsb/UE4_Assimp/)
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status)) * [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port. * [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
* [Rust](https://github.com/jkvargas/russimp)
### 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 this: Open Asset Import Library is implemented in C++. The directory structure looks like:
/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
/include Public header C and C++ header files /include Public header C and C++ header files
/scripts Scripts are used to generate the loading code for some formats /scripts Scripts 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 use cases for Assimp /samples A small number of samples to illustrate possible
use cases for Assimp
The source code is organized in the following way: 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 of the format code/<FormatName> Implementation for import and export for the format
### Where to get help ###
For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
(CHMs for Windows are included in some release packages and should be located right here in the root folder).
If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
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
@ -98,6 +101,15 @@ Become a financial contributor and help us sustain our community. [[Contribute](
<a href="https://opencollective.com/assimp"><img src="https://opencollective.com/assimp/individuals.svg?width=890"></a> <a href="https://opencollective.com/assimp"><img src="https://opencollective.com/assimp/individuals.svg?width=890"></a>
Monthly donations via Patreon:
<br>[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp)
<br>
One-off donations via PayPal:
<br>[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
<br>
#### Organizations #### Organizations
@ -113,4 +125,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

@ -1,16 +0,0 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.2.4 | :white_check_mark: |
## Reporting a Vulnerability
If you have found any security vulnerability you can contact us via
kim.kulling@googlemail.com

81
appveyor.yml 100644
View File

@ -0,0 +1,81 @@
# AppVeyor file
# http://www.appveyor.com/docs/appveyor-yml
# clone directory
clone_folder: c:\projects\assimp
clone_depth: 1
# branches to build
branches:
# whitelist
only:
- master
matrix:
fast_finish: true
image:
- Visual Studio 2013
#- Visual Studio 2015
#- Visual Studio 2017
- Visual Studio 2019
#- MinGW
platform:
- Win32
- x64
configuration: Release
install:
- set PATH=C:\Ruby24-x64\bin;%PATH%
- set CMAKE_DEFINES -DASSIMP_WERROR=ON
- if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH%
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" set CMAKE_GENERATOR_NAME=Visual Studio 16 2019
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" -A %platform% .
# Rename sh.exe as sh.exe in PATH interferes with MinGW - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
- rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe"
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe
cache:
- code\assimp.dir\%CONFIGURATION%
- contrib\zlib\zlibstatic.dir\%CONFIGURATION%
- contrib\zlib\zlib.dir\%CONFIGURATION%
- tools\assimp_cmd\assimp_cmd.dir\%CONFIGURATION%
- tools\assimp_view\assimp_viewer.dir\%CONFIGURATION%
- test\unit.dir\%CONFIGURATION%
- bin\.mtime_cache
before_build:
- echo NUMBER_OF_PROCESSORS=%NUMBER_OF_PROCESSORS%
- ruby scripts\AppVeyor\mtime_cache -g scripts\AppVeyor\cacheglobs.txt -c bin\.mtime_cache\cache.json
build_script:
cmake --build . --config Release -- /maxcpucount:2
after_build:
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
if "%platform%"=="x64" (
iscc packaging\windows-innosetup\script_x64.iss
) else (
iscc packaging\windows-innosetup\script_x86.iss
)
)
- 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\*
test_script:
- cmd: bin\%CONFIGURATION%\unit.exe --gtest_output=xml:testout.xml
on_finish:
- ps: (new-object net.webclient).UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\testout.xml))
artifacts:
- path: assimp.7z
name: assimp_lib

View File

@ -0,0 +1,48 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
# Copyright (c) 2006-2020, assimp team
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the
# following conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the assimp team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the assimp team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#----------------------------------------------------------------------
set( PACKAGE_VERSION "@ASSIMP_VERSION@" )
if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@")
set(PACKAGE_VERSION_EXACT 1)
endif()
if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_VERSION@" )
set(PACKAGE_VERSION_COMPATIBLE 1)
elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" )
# for now backward compatible if minor version is less
if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ )
set(PACKAGE_VERSION_COMPATIBLE 1)
endif()
endif()
set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@")

View File

@ -0,0 +1 @@
include(${CMAKE_CURRENT_LIST_DIR}/assimpTargets.cmake)

View File

@ -0,0 +1,126 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Debug".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
if(MSVC)
if(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
else()
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC_VERSION LESS 1910)
set(MSVC_PREFIX "vc140")
elseif( MSVC_VERSION LESS 1920)
set(MSVC_PREFIX "vc141")
elseif( MSVC_VERSION LESS 1930)
set(MSVC_PREFIX "vc142")
else()
set(MSVC_PREFIX "vc150")
endif()
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_IMPLIB_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
else()
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
endif()
else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
else()
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Debug"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
endif()
endif()
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
set( ASSIMP_LINK_FLAGS "" )
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
if(ASSIMP_BUILD_SHARED_LIBS)
set( ASSIMP_LIBRARIES ${sharedLibraryName})
else()
set( ASSIMP_LIBRARIES ${staticLibraryName})
endif()
# for compatibility with pkg-config
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
MARK_AS_ADVANCED(
ASSIMP_ROOT_DIR
ASSIMP_CXX_FLAGS
ASSIMP_LINK_FLAGS
ASSIMP_INCLUDE_DIRS
ASSIMP_LIBRARIES
ASSIMP_CFLAGS_OTHER
ASSIMP_LDFLAGS_OTHER
ASSIMP_LIBRARY_SUFFIX
ASSIMP_BUILD_SHARED_LIBS
)

View File

@ -0,0 +1,127 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
if(MSVC)
if(MSVC_TOOLSET_VERSION)
set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
else()
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC_VERSION LESS 1910)
set(MSVC_PREFIX "vc140")
elseif( MSVC_VERSION LESS 1920)
set(MSVC_PREFIX "vc141")
elseif( MSVC_VERSION LESS 1930)
set(MSVC_PREFIX "vc142")
else()
set(MSVC_PREFIX "vc150")
endif()
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_IMPLIB_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
else()
set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
endif()
else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
else()
set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
# Import target "assimp::assimp" for configuration "Release"
set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(assimp::assimp PROPERTIES
IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
)
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
endif()
endif()
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
set( ASSIMP_LINK_FLAGS "" )
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
if(ASSIMP_BUILD_SHARED_LIBS)
set( ASSIMP_LIBRARIES ${sharedLibraryName})
else()
set( ASSIMP_LIBRARIES ${staticLibraryName})
endif()
# for compatibility with pkg-config
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
MARK_AS_ADVANCED(
ASSIMP_ROOT_DIR
ASSIMP_CXX_FLAGS
ASSIMP_LINK_FLAGS
ASSIMP_INCLUDE_DIRS
ASSIMP_LIBRARIES
ASSIMP_CFLAGS_OTHER
ASSIMP_LDFLAGS_OTHER
ASSIMP_LIBRARY_SUFFIX
ASSIMP_BUILD_SHARED_LIBS
)

View File

@ -0,0 +1,91 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function
cmake_policy(SET CMP0012 NEW)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget assimp::assimp)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Create imported target assimp::assimp
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
set_target_properties(assimp::assimp PROPERTIES
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
INTERFACE_assimp_MAJOR_VERSION "1"
INTERFACE_INCLUDE_DIRECTORIES "@CMAKE_INSTALL_FULL_INCLUDEDIR@"
#INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
endif()
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/assimpTargets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
if(NOT EXISTS "${file}" )
message(FATAL_ERROR "The imported target \"${target}\" references the file
\"${file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

View File

@ -55,7 +55,7 @@ if(WIN32) # The only platform it makes sense to check for DirectX SDK
endif(CMAKE_CL_64) endif(CMAKE_CL_64)
find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_DXERR_LIBRARY NAMES DxErr DxErr9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) find_library(DirectX_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})

View File

@ -0,0 +1,17 @@
# Find IrrXMl from irrlicht project
#
# Find LibIrrXML headers and library
#
# IRRXML_FOUND - IrrXML found
# IRRXML_INCLUDE_DIR - Headers location
# IRRXML_LIBRARY - IrrXML main library
find_path(IRRXML_INCLUDE_DIR irrXML.h
PATH_SUFFIXES include/irrlicht include/irrxml)
find_library(IRRXML_LIBRARY IrrXML)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IrrXML REQUIRED_VARS IRRXML_INCLUDE_DIR IRRXML_LIBRARY)
mark_as_advanced(IRRXML_INCLUDE_DIR IRRXML_LIBRARY)

View File

@ -54,7 +54,7 @@ macro(clear_if_changed TESTVAR)
set(${var} "NOTFOUND" CACHE STRING "x" FORCE) set(${var} "NOTFOUND" CACHE STRING "x" FORCE)
endforeach(var) endforeach(var)
endif () endif ()
set(${TESTVAR}_INT_CHECK "${${TESTVAR}}" CACHE INTERNAL "x" FORCE) set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE)
endmacro(clear_if_changed) endmacro(clear_if_changed)
# Try to get some hints from pkg-config, if available # Try to get some hints from pkg-config, if available

View File

@ -16,5 +16,5 @@ set(RT_LIBRARIES ${RT_LIBRARY})
# handle the QUIETLY and REQUIRED arguments and set # handle the QUIETLY and REQUIRED arguments and set
# RT_FOUND to TRUE if all listed variables are TRUE # RT_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RT DEFAULT_MSG RT_LIBRARY) find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY)
mark_as_advanced(RT_LIBRARY) mark_as_advanced(RT_LIBRARY)

View File

@ -1,19 +0,0 @@
@PACKAGE_INIT@
find_package(RapidJSON CONFIG REQUIRED)
find_package(ZLIB CONFIG REQUIRED)
find_package(utf8cpp CONFIG REQUIRED)
find_package(minizip CONFIG REQUIRED)
find_package(openddlparser CONFIG REQUIRED)
find_package(poly2tri CONFIG REQUIRED)
find_package(polyclipping CONFIG REQUIRED)
find_package(zip CONFIG REQUIRED)
find_package(pugixml CONFIG REQUIRED)
find_package(stb CONFIG REQUIRED)
if(@ASSIMP_BUILD_DRACO@)
find_package(draco CONFIG REQUIRED)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")

View File

@ -1,9 +0,0 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
set(ASSIMP_ROOT_DIR ${PACKAGE_PREFIX_DIR})
set(ASSIMP_LIBRARIES assimp::assimp)
set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
get_property(ASSIMP_INCLUDE_DIRS TARGET assimp::assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
set(ASSIMP_LIBRARY_DIRS "")

View File

@ -1,4 +1,4 @@
# Copyright (c) 2013-2019, Ruslan Baratov # Copyright (c) 2013-2018, Ruslan Baratov
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -22,16 +22,45 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This is a gate file to Hunter package manager.
# Include this file using `include` command and add package you need, example:
#
# cmake_minimum_required(VERSION 3.2)
#
# include("cmake/HunterGate.cmake")
# HunterGate(
# URL "https://github.com/path/to/hunter/archive.tar.gz"
# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
# )
#
# project(MyProject)
#
# hunter_add_package(Foo)
# hunter_add_package(Boo COMPONENTS Bar Baz)
#
# Projects:
# * https://github.com/hunter-packages/gate/
# * https://github.com/ruslo/hunter
option(HUNTER_ENABLED "Enable Hunter package manager support" ON) option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
if(HUNTER_ENABLED)
if(CMAKE_VERSION VERSION_LESS "3.2")
message(
FATAL_ERROR
"At least CMake version 3.2 required for Hunter dependency management."
" Update CMake or set HUNTER_ENABLED to OFF."
)
endif()
endif()
include(CMakeParseArguments) # cmake_parse_arguments include(CMakeParseArguments) # cmake_parse_arguments
option(HUNTER_STATUS_PRINT "Print working status" ON) option(HUNTER_STATUS_PRINT "Print working status" ON)
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors") set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
function(hunter_gate_status_print) function(hunter_gate_status_print)
if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
@ -50,9 +79,9 @@ function(hunter_gate_status_debug)
endif() endif()
endfunction() endfunction()
function(hunter_gate_error_page error_page) function(hunter_gate_wiki wiki_page)
message("------------------------------ ERROR ------------------------------") message("------------------------------ WIKI -------------------------------")
message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") message(" ${HUNTER_WIKI}/${wiki_page}")
message("-------------------------------------------------------------------") message("-------------------------------------------------------------------")
message("") message("")
message(FATAL_ERROR "") message(FATAL_ERROR "")
@ -65,13 +94,14 @@ function(hunter_gate_internal_error)
endforeach() endforeach()
message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("") message("")
hunter_gate_error_page("error.internal") hunter_gate_wiki("error.internal")
endfunction() endfunction()
function(hunter_gate_fatal_error) function(hunter_gate_fatal_error)
cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
if("${hunter_ERROR_PAGE}" STREQUAL "") string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
hunter_gate_internal_error("Expected ERROR_PAGE") if(have_no_wiki)
hunter_gate_internal_error("Expected wiki")
endif() endif()
message("") message("")
foreach(x ${hunter_UNPARSED_ARGUMENTS}) foreach(x ${hunter_UNPARSED_ARGUMENTS})
@ -79,11 +109,11 @@ function(hunter_gate_fatal_error)
endforeach() endforeach()
message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
message("") message("")
hunter_gate_error_page("${hunter_ERROR_PAGE}") hunter_gate_wiki("${hunter_WIKI}")
endfunction() endfunction()
function(hunter_gate_user_error) function(hunter_gate_user_error)
hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
endfunction() endfunction()
function(hunter_gate_self root version sha1 result) function(hunter_gate_self root version sha1 result)
@ -165,7 +195,7 @@ function(hunter_gate_detect_root)
hunter_gate_fatal_error( hunter_gate_fatal_error(
"Can't detect HUNTER_ROOT" "Can't detect HUNTER_ROOT"
ERROR_PAGE "error.detect.hunter.root" WIKI "error.detect.hunter.root"
) )
endfunction() endfunction()
@ -184,7 +214,7 @@ function(hunter_gate_download dir)
"Settings:" "Settings:"
" HUNTER_ROOT: ${HUNTER_GATE_ROOT}" " HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
" HUNTER_SHA1: ${HUNTER_GATE_SHA1}" " HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
ERROR_PAGE "error.run.install" WIKI "error.run.install"
) )
endif() endif()
string(COMPARE EQUAL "${dir}" "" is_bad) string(COMPARE EQUAL "${dir}" "" is_bad)
@ -370,7 +400,7 @@ macro(HunterGate)
hunter_gate_fatal_error( hunter_gate_fatal_error(
"Please set HunterGate *before* 'project' command. " "Please set HunterGate *before* 'project' command. "
"Detected project: ${PROJECT_NAME}" "Detected project: ${PROJECT_NAME}"
ERROR_PAGE "error.huntergate.before.project" WIKI "error.huntergate.before.project"
) )
endif() endif()
@ -440,7 +470,7 @@ macro(HunterGate)
"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
"(Use at your own risk!)" "(Use at your own risk!)"
ERROR_PAGE "error.spaces.in.hunter.root" WIKI "error.spaces.in.hunter.root"
) )
endif() endif()
endif() endif()

View File

@ -0,0 +1,14 @@
@PACKAGE_INIT@
find_package(RapidJSON CONFIG REQUIRED)
find_package(ZLIB CONFIG REQUIRED)
find_package(utf8 CONFIG REQUIRED)
find_package(irrXML CONFIG REQUIRED)
find_package(minizip CONFIG REQUIRED)
find_package(openddlparser CONFIG REQUIRED)
find_package(poly2tri CONFIG REQUIRED)
find_package(polyclipping CONFIG REQUIRED)
find_package(zip CONFIG REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")

View File

@ -0,0 +1,707 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter.cpp
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
// Header files, Assimp.
#include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
#include <assimp/fast_atof.h>
#include <assimp/DefaultIOSystem.h>
// Header files, stdlib.
#include <memory>
namespace Assimp
{
/// \var aiImporterDesc AMFImporter::Description
/// Conastant which hold importer description
const aiImporterDesc AMFImporter::Description = {
"Additive manufacturing file format(AMF) Importer",
"smalcom",
"",
"See documentation in source code. Chapter: Limitations.",
aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
0,
0,
0,
0,
"amf"
};
void AMFImporter::Clear()
{
mNodeElement_Cur = nullptr;
mUnit.clear();
mMaterial_Converted.clear();
mTexture_Converted.clear();
// Delete all elements
if(!mNodeElement_List.empty())
{
for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }
mNodeElement_List.clear();
}
}
AMFImporter::~AMFImporter()
{
if(mReader != nullptr) delete mReader;
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
Clear();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const
{
for(CAMFImporter_NodeElement* ne: mNodeElement_List)
{
if((ne->ID == pID) && (ne->Type == pType))
{
if(pNodeElement != nullptr) *pNodeElement = ne;
return true;
}
}// for(CAMFImporter_NodeElement* ne: mNodeElement_List)
return false;
}
bool AMFImporter::Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const
{
aiString node_name(pID.c_str());
for(aiNode* node: pNodeList)
{
if(node->mName == node_name)
{
if(pNode != nullptr) *pNode = node;
return true;
}
}// for(aiNode* node: pNodeList)
return false;
}
bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const
{
for(const SPP_Material& mat: mMaterial_Converted)
{
if(mat.ID == pID)
{
if(pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
return true;
}
}// for(const SPP_Material& mat: mMaterial_Converted)
return false;
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: throw set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::Throw_CloseNotFound(const std::string& pNode)
{
throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
}
void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName)
{
throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
}
void AMFImporter::Throw_IncorrectAttrValue(const std::string& pAttrName)
{
throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
}
void AMFImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription)
{
throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
}
void AMFImporter::Throw_ID_NotFound(const std::string& pID) const
{
throw DeadlyImportError("Not found node with name \"" + pID + "\".");
}
/*********************************************************************************************************************************************/
/************************************************************* Functions: XML set ************************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::XML_CheckNode_MustHaveChildren()
{
if(mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children.");
}
void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
{
static const size_t Uns_Skip_Len = 3;
const char* Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
static bool skipped_before[Uns_Skip_Len] = { false, false, false };
std::string nn(mReader->getNodeName());
bool found = false;
bool close_found = false;
size_t sk_idx;
for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
{
if(nn != Uns_Skip[sk_idx]) continue;
found = true;
if(mReader->isEmptyElement())
{
close_found = true;
goto casu_cres;
}
while(mReader->read())
{
if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName()))
{
close_found = true;
goto casu_cres;
}
}
}// for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
casu_cres:
if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
if(!close_found) Throw_CloseNotFound(nn);
if(!skipped_before[sk_idx])
{
skipped_before[sk_idx] = true;
ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
}
}
bool AMFImporter::XML_SearchNode(const std::string& pNodeName)
{
while(mReader->read())
{
if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
}
return false;
}
bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
{
std::string val(mReader->getAttributeValue(pAttrIdx));
if((val == "false") || (val == "0"))
return false;
else if((val == "true") || (val == "1"))
return true;
else
throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
}
float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
{
std::string val;
float tvalf;
ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx)
{
return strtoul10(mReader->getAttributeValue(pAttrIdx));
}
float AMFImporter::XML_ReadNode_GetVal_AsFloat()
{
std::string val;
float tvalf;
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32()
{
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
return strtoul10(mReader->getNodeData());
}
void AMFImporter::XML_ReadNode_GetVal_AsString(std::string& pValue)
{
if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
if(mReader->getNodeType() != irr::io::EXN_TEXT)
throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
pValue = mReader->getNodeData();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: parse set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode)
{
mNodeElement_Cur->Child.push_back(pNode);// add new element to current element child list.
mNodeElement_Cur = pNode;// switch current element to new one.
}
void AMFImporter::ParseHelper_Node_Exit()
{
// check if we can walk up.
if(mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
}
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString)
{
size_t instr_len;
pOutString.clear();
instr_len = strlen(pInStr);
if(!instr_len) return;
pOutString.reserve(instr_len * 3 / 2);
// check and correct floats in format ".x". Must be "x.y".
if(pInStr[0] == '.') pOutString.push_back('0');
pOutString.push_back(pInStr[0]);
for(size_t ci = 1; ci < instr_len; ci++)
{
if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t')))
{
pOutString.push_back('0');
pOutString.push_back('.');
}
else
{
pOutString.push_back(pInStr[ci]);
}
}
}
static bool ParseHelper_Decode_Base64_IsBase64(const char pChar)
{
return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
}
void AMFImporter::ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const
{
// With help from
// René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html
const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uint8_t tidx = 0;
uint8_t arr4[4], arr3[3];
// check input data
if(pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
// prepare output place
pOutputData.clear();
pOutputData.reserve(pInputBase64.size() / 4 * 3);
for(size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--)
{
if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
{
arr4[tidx++] = pInputBase64[in_idx++];
if(tidx == 4)
{
for(tidx = 0; tidx < 4; tidx++) arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]);
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for(tidx = 0; tidx < 3; tidx++) pOutputData.push_back(arr3[tidx]);
tidx = 0;
}// if(tidx == 4)
}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
else
{
in_idx++;
}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else
}
if(tidx)
{
for(uint8_t i = tidx; i < 4; i++) arr4[i] = 0;
for(uint8_t i = 0; i < 4; i++) arr4[i] = (uint8_t)(base64_chars.find(arr4[i]));
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
for(uint8_t i = 0; i < (tidx - 1); i++) pOutputData.push_back(arr3[i]);
}
}
void AMFImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
{
irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
}
// generate a XML reader for it
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
//
// start reading
// search for root tag <amf>
if(XML_SearchNode("amf"))
ParseNode_Root();
else
throw DeadlyImportError("Root node \"amf\" not found.");
delete mReader;
// restore old XMLreader
mReader = OldReader;
}
// <amf
// unit="" - The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
// version="" - Version of file format.
// >
// </amf>
// Root XML element.
// Multi elements - No.
void AMFImporter::ParseNode_Root()
{
std::string unit, version;
CAMFImporter_NodeElement *ne( nullptr );
// Read attributes for node <amf>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND_WSKIP;
// Check attributes
if(!mUnit.empty())
{
if((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit");
}
// create root node element.
ne = new CAMFImporter_NodeElement_Root(nullptr);
mNodeElement_Cur = ne;// set first "current" element
// and assign attribute's values
((CAMFImporter_NodeElement_Root*)ne)->Unit = unit;
((CAMFImporter_NodeElement_Root*)ne)->Version = version;
// Check for child nodes
if(!mReader->isEmptyElement())
{
MACRO_NODECHECK_LOOPBEGIN("amf");
if(XML_CheckNode_NameEqual("object")) { ParseNode_Object(); continue; }
if(XML_CheckNode_NameEqual("material")) { ParseNode_Material(); continue; }
if(XML_CheckNode_NameEqual("texture")) { ParseNode_Texture(); continue; }
if(XML_CheckNode_NameEqual("constellation")) { ParseNode_Constellation(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("amf");
mNodeElement_Cur = ne;// force restore "current" element
}// if(!mReader->isEmptyElement())
mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
}
// <constellation
// id="" - The Object ID of the new constellation being defined.
// >
// </constellation>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Constellation()
{
std::string id;
CAMFImporter_NodeElement* ne( nullptr );
// Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new grouping object.
ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur);
CAMFImporter_NodeElement_Constellation& als = *((CAMFImporter_NodeElement_Constellation*)ne);// alias for convenience
if(!id.empty()) als.ID = id;
// Check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("constellation");
if(XML_CheckNode_NameEqual("instance")) { ParseNode_Instance(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("constellation");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <instance
// objectid="" - The Object ID of the new constellation being defined.
// >
// </instance>
// A collection of objects or constellations with specific relative locations.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Instance()
{
std::string objectid;
CAMFImporter_NodeElement* ne( nullptr );
// Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// used object id must be defined, check that.
if(objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
// create and define new grouping object.
ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);// alias for convenience
als.ObjectID = objectid;
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool read_flag[6] = { false, false, false, false, false, false };
als.Delta.Set(0, 0, 0);
als.Rotation.Set(0, 0, 0);
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("instance");
MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
MACRO_NODECHECK_LOOPEND("instance");
ParseHelper_Node_Exit();
// also convert degrees to radians.
als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <object
// id="" - A unique ObjectID for the new object being defined.
// >
// </object>
// An object definition.
// Multi elements - Yes.
// Parent element - <amf>.
void AMFImporter::ParseNode_Object()
{
std::string id;
CAMFImporter_NodeElement* ne( nullptr );
// Read attributes for node <object>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new geometry object.
ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur);
CAMFImporter_NodeElement_Object& als = *((CAMFImporter_NodeElement_Object*)ne);// alias for convenience
if(!id.empty()) als.ID = id;
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("object");
if(XML_CheckNode_NameEqual("color"))
{
// Check if color already defined for object.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if(XML_CheckNode_NameEqual("mesh")) { ParseNode_Mesh(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("object");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
// <metadata
// type="" - The type of the attribute.
// >
// </metadata>
// Specify additional information about an entity.
// Multi elements - Yes.
// Parent element - <amf>, <object>, <volume>, <material>, <vertex>.
//
// Reserved types are:
// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user.
// "Description" - A description of the content of the entity
// "URL" - A link to an external resource relating to the entity
// "Author" - Specifies the name(s) of the author(s) of the entity
// "Company" - Specifying the company generating the entity
// "CAD" - specifies the name of the originating CAD software and version
// "Revision" - specifies the revision of the entity
// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
void AMFImporter::ParseNode_Metadata()
{
std::string type, value;
CAMFImporter_NodeElement* ne( nullptr );
// read attribute
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// and value of node.
value = mReader->getNodeData();
// Create node element and assign read data.
ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur);
((CAMFImporter_NodeElement_Metadata*)ne)->Type = type;
((CAMFImporter_NodeElement_Metadata*)ne)->Value = value;
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
}
/*********************************************************************************************************************************************/
/******************************************************** Functions: BaseImporter set ********************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const
{
const std::string extension = GetExtension(pFile);
if ( extension == "amf" ) {
return true;
}
if(!extension.length() || pCheckSig)
{
const char* tokens[] = { "<amf" };
return SearchFileHeaderForToken( pIOHandler, pFile, tokens, 1 );
}
return false;
}
void AMFImporter::GetExtensionList(std::set<std::string>& pExtensionList)
{
pExtensionList.insert("amf");
}
const aiImporterDesc* AMFImporter::GetInfo () const
{
return &Description;
}
void AMFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
Clear();// delete old graph.
ParseFile(pFile, pIOHandler);
Postprocess_BuildScene(pScene);
// scene graph is ready, exit.
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -52,9 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cctype> #include <cctype>
#include <memory> #include <memory>
namespace Assimp { using namespace Assimp;
static constexpr unsigned int NotSet = 0xcdcdcdcd; static const 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,8 +68,8 @@ 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 (std::string::iterator it = s.begin(); it != s.end(); ++it) {
it = static_cast<char>(::tolower(static_cast<unsigned char>(it))); *it = static_cast<char>(::tolower(*it));
} }
if (std::string::npos == s.find("default")) continue; if (std::string::npos == s.find("default")) continue;
@ -79,7 +79,12 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
mScene->mMaterials[i].mDiffuse.r != mScene->mMaterials[i].mDiffuse.r !=
mScene->mMaterials[i].mDiffuse.b) continue; mScene->mMaterials[i].mDiffuse.b) continue;
if (ContainsTextures(i)) { if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
continue; continue;
} }
idx = i; idx = i;
@ -207,7 +212,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
// Be sure this is only done for the first material // Be sure this is only done for the first material
mBackgroundImage = std::string(); mBackgroundImage = std::string("");
} }
// At first add the base ambient color of the scene to the material // At first add the base ambient color of the scene to the material
@ -262,7 +267,6 @@ 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]];
case D3DS::Discreet3DS::Gouraud: case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; eShading = aiShadingMode_Gouraud;
@ -593,7 +597,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 be able to return valid cameras/lights even if no scenegraph is given. // to 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);
@ -643,17 +647,11 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
} }
// Allocate storage for children // Allocate storage for children
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size()); pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
pcOut->mNumChildren = size;
if (size == 0) {
return;
}
pcOut->mChildren = new aiNode *[pcIn->mChildren.size()]; pcOut->mChildren = new aiNode *[pcIn->mChildren.size()];
// Recursively process all children // Recursively process all children
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
for (unsigned int i = 0; i < size; ++i) { for (unsigned int i = 0; i < size; ++i) {
pcOut->mChildren[i] = new aiNode(); pcOut->mChildren[i] = new aiNode();
pcOut->mChildren[i]->mParent = pcOut; pcOut->mChildren[i]->mParent = pcOut;
@ -715,7 +713,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
pcNode->mNumMeshes = 1; pcNode->mNumMeshes = 1;
// Build a name for the node // Build a name for the node
pcNode->mName.length = ai_snprintf(pcNode->mName.data, AI_MAXLEN, "3DSMesh_%u", i); pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u", i);
} }
// Build dummy nodes for all cameras // Build dummy nodes for all cameras
@ -811,6 +809,4 @@ void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
} }
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -52,13 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/Exceptional.h>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <memory> #include <memory>
using namespace Assimp;
namespace Assimp { namespace Assimp {
using namespace D3DS; using namespace D3DS;
namespace { namespace {
@ -103,14 +102,13 @@ private:
// preserves the mesh's given name if it has one. |index| is the index // preserves the mesh's given name if it has one. |index| is the index
// of the mesh in |aiScene::mMeshes|. // of the mesh in |aiScene::mMeshes|.
std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) { std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) {
static const char underscore = '_'; static const std::string underscore = "_";
char postfix[10] = { 0 }; char postfix[10] = { 0 };
ASSIMP_itoa10(postfix, index); ASSIMP_itoa10(postfix, index);
std::string result = node.mName.C_Str(); std::string result = node.mName.C_Str();
if (mesh.mName.length > 0) { if (mesh.mName.length > 0) {
result += underscore; result += underscore + mesh.mName.C_Str();
result += mesh.mName.C_Str();
} }
return result + underscore + postfix; return result + underscore + postfix;
} }
@ -210,7 +208,9 @@ Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, con
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Discreet3DSExporter::~Discreet3DSExporter() = default; Discreet3DSExporter::~Discreet3DSExporter() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) { int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) {
@ -296,12 +296,6 @@ void Discreet3DSExporter::WriteMaterials() {
WriteColor(color); WriteColor(color);
} }
float f;
if (mat.Get(AI_MATKEY_OPACITY, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TRANSPARENCY);
WritePercentChunk(1.0f - f);
}
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
WriteColor(color); WriteColor(color);
@ -329,7 +323,6 @@ void Discreet3DSExporter::WriteMaterials() {
case aiShadingMode_Blinn: case aiShadingMode_Blinn:
case aiShadingMode_CookTorrance: case aiShadingMode_CookTorrance:
case aiShadingMode_Fresnel: case aiShadingMode_Fresnel:
case aiShadingMode_PBR_BRDF: // Possibly should be Discreet3DS::Metal in some cases but this is undocumented
shading_mode_out = Discreet3DS::Phong; shading_mode_out = Discreet3DS::Phong;
break; break;
@ -340,6 +333,7 @@ void Discreet3DSExporter::WriteMaterials() {
writer.PutU2(static_cast<uint16_t>(shading_mode_out)); writer.PutU2(static_cast<uint16_t>(shading_mode_out));
} }
float f;
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS); ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
WritePercentChunk(f); WritePercentChunk(f);
@ -356,10 +350,7 @@ void Discreet3DSExporter::WriteMaterials() {
writer.PutI2(1); writer.PutI2(1);
} }
// Fallback to BASE_COLOR if no DIFFUSE WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
if (!WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE))
WriteTexture(mat, aiTextureType_BASE_COLOR, Discreet3DS::CHUNK_MAT_TEXTURE);
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP); WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP); WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP); WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
@ -370,21 +361,20 @@ void Discreet3DSExporter::WriteMaterials() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// returns true if the texture existed void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
bool Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
aiString path; aiString path;
aiTextureMapMode map_mode[2] = { aiTextureMapMode map_mode[2] = {
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
}; };
ai_real blend = 1.0; ai_real blend = 1.0;
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) { if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
return false; return;
} }
// TODO: handle embedded textures properly // TODO: handle embedded textures properly
if (path.data[0] == '*') { if (path.data[0] == '*') {
ASSIMP_LOG_ERROR("Ignoring embedded texture for export: ", path.C_Str()); ASSIMP_LOG_ERROR("Ignoring embedded texture for export: " + std::string(path.C_Str()));
return false; return;
} }
ChunkWriter chunk(writer, chunk_flags); ChunkWriter chunk(writer, chunk_flags);
@ -406,7 +396,6 @@ bool Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type
writer.PutU2(val); writer.PutU2(val);
} }
// TODO: export texture transformation (i.e. UV offset, scale, rotation) // TODO: export texture transformation (i.e. UV offset, scale, rotation)
return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -450,7 +439,7 @@ void Discreet3DSExporter::WriteMeshes() {
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices); const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
writer.PutU2(count); writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) { for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D &v = mesh.mVertices[i]; const aiVector3D &v = trafo * mesh.mVertices[i];
writer.PutF4(v.x); writer.PutF4(v.x);
writer.PutF4(v.y); writer.PutF4(v.y);
writer.PutF4(v.z); writer.PutF4(v.z);
@ -512,16 +501,11 @@ void Discreet3DSExporter::WriteMeshes() {
// Transformation matrix by which the mesh vertices have been pre-transformed with. // Transformation matrix by which the mesh vertices have been pre-transformed with.
{ {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX); ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX);
// Store rotation 3x3 matrix row wise for (unsigned int r = 0; r < 4; ++r) {
for (unsigned int r = 0; r < 3; ++r) {
for (unsigned int c = 0; c < 3; ++c) { for (unsigned int c = 0; c < 3; ++c) {
writer.PutF4(trafo[r][c]); writer.PutF4(trafo[r][c]);
} }
} }
// Store translation sub vector column wise
for (unsigned int r = 0; r < 3; ++r) {
writer.PutF4(trafo[r][3]);
}
} }
} }
} }

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -56,7 +57,8 @@ struct aiNode;
struct aiMaterial; struct aiMaterial;
struct aiMesh; struct aiMesh;
namespace Assimp { namespace Assimp
{
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/** /**
@ -71,7 +73,7 @@ public:
private: private:
void WriteMeshes(); void WriteMeshes();
void WriteMaterials(); void WriteMaterials();
bool WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags); void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
void WriteFaceMaterialChunk(const aiMesh& mesh); void WriteFaceMaterialChunk(const aiMesh& mesh);
int WriteHierarchy(const aiNode& node, int level, int sibling_level); int WriteHierarchy(const aiNode& node, int level, int sibling_level);
void WriteString(const std::string& s); void WriteString(const std::string& s);
@ -86,7 +88,7 @@ private:
std::map<const aiNode*, aiMatrix4x4> trafos; std::map<const aiNode*, aiMatrix4x4> trafos;
using MeshesByNodeMap = std::multimap<const aiNode*, unsigned int>; typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
MeshesByNodeMap meshes; MeshesByNodeMap meshes;
}; };

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/light.h> #include <assimp/light.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/qnan.h> #include <assimp/qnan.h>
#include <cstdio> //sprintf #include <stdio.h> //sprintf
namespace Assimp { namespace Assimp {
namespace D3DS { namespace D3DS {
@ -61,10 +61,20 @@ namespace D3DS {
#include <assimp/Compiler/pushpack1.h> #include <assimp/Compiler/pushpack1.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Defines chunks and data structures. /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
* and data structures.
*/ */
namespace Discreet3DS { class Discreet3DS {
private:
Discreet3DS() AI_NO_EXCEPT {
// empty
}
~Discreet3DS() {
// empty
}
public:
//! data structure for a single chunk in a .3ds file //! data structure for a single chunk in a .3ds file
struct Chunk { struct Chunk {
uint16_t Flag; uint16_t Flag;
@ -259,7 +269,7 @@ namespace Discreet3DS {
// Specifies the file name of a texture // Specifies the file name of a texture
CHUNK_MAPFILE = 0xA300, CHUNK_MAPFILE = 0xA300,
// Specifies whether a material requires two-sided rendering // Specifies whether a materail requires two-sided rendering
CHUNK_MAT_TWO_SIDE = 0xA081, CHUNK_MAT_TWO_SIDE = 0xA081,
// ******************************************************************** // ********************************************************************
@ -304,17 +314,16 @@ namespace Discreet3DS {
// camera sub-chunks // camera sub-chunks
CHUNK_CAM_RANGES = 0x4720 CHUNK_CAM_RANGES = 0x4720
}; };
} };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure representing a 3ds mesh face */ /** Helper structure representing a 3ds mesh face */
struct Face : public FaceWithSmoothingGroup { struct Face : public FaceWithSmoothingGroup {
}; };
#ifdef _MSC_VER #ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4315) #pragma warning(disable : 4315)
#endif // _MSC_VER #endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure representing a texture */ /** Helper structure representing a texture */
@ -322,6 +331,7 @@ struct Texture {
//! Default constructor //! Default constructor
Texture() AI_NO_EXCEPT Texture() AI_NO_EXCEPT
: mTextureBlend(0.0f), : mTextureBlend(0.0f),
mMapName(),
mOffsetU(0.0), mOffsetU(0.0),
mOffsetV(0.0), mOffsetV(0.0),
mScaleU(1.0), mScaleU(1.0),
@ -333,11 +343,51 @@ struct Texture {
mTextureBlend = get_qnan(); mTextureBlend = get_qnan();
} }
Texture(const Texture &other) = default; Texture(const Texture &other) :
mTextureBlend(other.mTextureBlend),
mMapName(other.mMapName),
mOffsetU(other.mOffsetU),
mOffsetV(other.mOffsetV),
mScaleU(other.mScaleU),
mScaleV(other.mScaleV),
mRotation(other.mRotation),
mMapMode(other.mMapMode),
bPrivate(other.bPrivate),
iUVSrc(other.iUVSrc) {
// empty
}
Texture(Texture &&other) AI_NO_EXCEPT = default; Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)),
mMapName(std::move(other.mMapName)),
mOffsetU(std::move(other.mOffsetU)),
mOffsetV(std::move(other.mOffsetV)),
mScaleU(std::move(other.mScaleU)),
mScaleV(std::move(other.mScaleV)),
mRotation(std::move(other.mRotation)),
mMapMode(std::move(other.mMapMode)),
bPrivate(std::move(other.bPrivate)),
iUVSrc(std::move(other.iUVSrc)) {
// empty
}
Texture &operator=(Texture &&other) AI_NO_EXCEPT = default; Texture &operator=(Texture &&other) AI_NO_EXCEPT {
if (this == &other) {
return *this;
}
mTextureBlend = std::move(other.mTextureBlend);
mMapName = std::move(other.mMapName);
mOffsetU = std::move(other.mOffsetU);
mOffsetV = std::move(other.mOffsetV);
mScaleU = std::move(other.mScaleU);
mScaleV = std::move(other.mScaleV);
mRotation = std::move(other.mRotation);
mMapMode = std::move(other.mMapMode);
bPrivate = std::move(other.bPrivate);
iUVSrc = std::move(other.iUVSrc);
return *this;
}
//! Specifies the blend factor for the texture //! Specifies the blend factor for the texture
ai_real mTextureBlend; ai_real mTextureBlend;
@ -362,16 +412,13 @@ struct Texture {
#include <assimp/Compiler/poppack1.h> #include <assimp/Compiler/poppack1.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure representing a 3ds material */ /** Helper structure representing a 3ds material */
struct Material { struct Material {
//! Default constructor has been deleted //! Default constructor has been deleted
Material() : Material() :
mName(), mName(),
mDiffuse(0.6f, 0.6f, 0.6f), mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
mSpecularExponent(ai_real(0.0)), mSpecularExponent(ai_real(0.0)),
mShininessStrength(ai_real(1.0)), mShininessStrength(ai_real(1.0)),
mShading(Discreet3DS::Gouraud), mShading(Discreet3DS::Gouraud),
@ -384,7 +431,7 @@ struct Material {
//! Constructor with explicit name //! Constructor with explicit name
explicit Material(const std::string &name) : explicit Material(const std::string &name) :
mName(name), mName(name),
mDiffuse(0.6f, 0.6f, 0.6f), mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
mSpecularExponent(ai_real(0.0)), mSpecularExponent(ai_real(0.0)),
mShininessStrength(ai_real(1.0)), mShininessStrength(ai_real(1.0)),
mShading(Discreet3DS::Gouraud), mShading(Discreet3DS::Gouraud),
@ -394,9 +441,83 @@ struct Material {
// empty // empty
} }
Material(const Material &other) = default; Material(const Material &other) :
mName(other.mName),
mDiffuse(other.mDiffuse),
mSpecularExponent(other.mSpecularExponent),
mShininessStrength(other.mShininessStrength),
mSpecular(other.mSpecular),
mAmbient(other.mAmbient),
mShading(other.mShading),
mTransparency(other.mTransparency),
sTexDiffuse(other.sTexDiffuse),
sTexOpacity(other.sTexOpacity),
sTexSpecular(other.sTexSpecular),
sTexReflective(other.sTexReflective),
sTexBump(other.sTexBump),
sTexEmissive(other.sTexEmissive),
sTexShininess(other.sTexShininess),
mBumpHeight(other.mBumpHeight),
mEmissive(other.mEmissive),
sTexAmbient(other.sTexAmbient),
mTwoSided(other.mTwoSided) {
// empty
}
virtual ~Material() = default; //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)),
mDiffuse(std::move(other.mDiffuse)),
mSpecularExponent(std::move(other.mSpecularExponent)),
mShininessStrength(std::move(other.mShininessStrength)),
mSpecular(std::move(other.mSpecular)),
mAmbient(std::move(other.mAmbient)),
mShading(std::move(other.mShading)),
mTransparency(std::move(other.mTransparency)),
sTexDiffuse(std::move(other.sTexDiffuse)),
sTexOpacity(std::move(other.sTexOpacity)),
sTexSpecular(std::move(other.sTexSpecular)),
sTexReflective(std::move(other.sTexReflective)),
sTexBump(std::move(other.sTexBump)),
sTexEmissive(std::move(other.sTexEmissive)),
sTexShininess(std::move(other.sTexShininess)),
mBumpHeight(std::move(other.mBumpHeight)),
mEmissive(std::move(other.mEmissive)),
sTexAmbient(std::move(other.sTexAmbient)),
mTwoSided(std::move(other.mTwoSided)) {
// empty
}
Material &operator=(Material &&other) AI_NO_EXCEPT {
if (this == &other) {
return *this;
}
mName = std::move(other.mName);
mDiffuse = std::move(other.mDiffuse);
mSpecularExponent = std::move(other.mSpecularExponent);
mShininessStrength = std::move(other.mShininessStrength),
mSpecular = std::move(other.mSpecular);
mAmbient = std::move(other.mAmbient);
mShading = std::move(other.mShading);
mTransparency = std::move(other.mTransparency);
sTexDiffuse = std::move(other.sTexDiffuse);
sTexOpacity = std::move(other.sTexOpacity);
sTexSpecular = std::move(other.sTexSpecular);
sTexReflective = std::move(other.sTexReflective);
sTexBump = std::move(other.sTexBump);
sTexEmissive = std::move(other.sTexEmissive);
sTexShininess = std::move(other.sTexShininess);
mBumpHeight = std::move(other.mBumpHeight);
mEmissive = std::move(other.mEmissive);
sTexAmbient = std::move(other.sTexAmbient);
mTwoSided = std::move(other.mTwoSided);
return *this;
}
virtual ~Material() {
// empty
}
//! Name of the material //! Name of the material
std::string mName; std::string mName;

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -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>
namespace Assimp { using namespace Assimp;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"Discreet 3DS Importer", "Discreet 3DS Importer",
"", "",
"", "",
@ -103,11 +103,28 @@ Discreet3DSImporter::Discreet3DSImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
Discreet3DSImporter::~Discreet3DSImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
static const uint16_t token[] = { 0x4d4d, 0x3dc2 /*, 0x3daa */ }; std::string extension = GetExtension(pFile);
return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token), 0, sizeof token[0]); if (extension == "3ds" || extension == "prj") {
return true;
}
if (!extension.length() || checkSig) {
uint16_t token[3];
token[0] = 0x4d4d;
token[1] = 0x3dc2;
//token[2] = 0x3daa;
return CheckMagicToken(pIOHandler, pFile, token, 2, 0, 2);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -126,17 +143,11 @@ void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void Discreet3DSImporter::InternReadFile(const std::string &pFile, void Discreet3DSImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) { aiScene *pScene, IOSystem *pIOHandler) {
StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
auto theFile = pIOHandler->Open(pFile, "rb");
if (!theFile) {
throw DeadlyImportError("3DS: Could not open ", pFile);
}
StreamReaderLE theStream(theFile);
// We should have at least one chunk // We should have at least one chunk
if (theStream.GetRemainingSize() < 16) { if (theStream.GetRemainingSize() < 16) {
throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile); throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
} }
this->stream = &theStream; this->stream = &theStream;
@ -153,7 +164,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
mRootNode->mHierarchyIndex = -1; mRootNode->mHierarchyIndex = -1;
mRootNode->mParent = nullptr; mRootNode->mParent = nullptr;
mMasterScale = 1.0f; mMasterScale = 1.0f;
mBackgroundImage = std::string(); mBackgroundImage = "";
bHasBG = false; bHasBG = false;
bIsPrj = false; bIsPrj = false;
@ -167,7 +178,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
// file. // file.
for (auto &mesh : mScene->mMeshes) { for (auto &mesh : mScene->mMeshes) {
if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) {
throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile); throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
} }
CheckIndices(mesh); CheckIndices(mesh);
MakeUnique(mesh); MakeUnique(mesh);
@ -255,22 +266,14 @@ void Discreet3DSImporter::ParseMainChunk() {
case Discreet3DS::CHUNK_PRJ: case Discreet3DS::CHUNK_PRJ:
bIsPrj = true; bIsPrj = true;
break;
case Discreet3DS::CHUNK_MAIN: case Discreet3DS::CHUNK_MAIN:
ParseEditorChunk(); ParseEditorChunk();
break; break;
}; };
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
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -295,7 +298,7 @@ void Discreet3DSImporter::ParseEditorChunk() {
// print the version number // print the version number
char buff[10]; char buff[10];
ASSIMP_itoa10(buff, stream->GetI2()); ASSIMP_itoa10(buff, stream->GetI2());
ASSIMP_LOG_INFO("3DS file format version: ", buff); ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
} break; } break;
}; };
ASSIMP_3DS_END_CHUNK(); ASSIMP_3DS_END_CHUNK();
@ -320,7 +323,7 @@ void Discreet3DSImporter::ParseObjectChunk() {
case Discreet3DS::CHUNK_MAT_MATERIAL: case Discreet3DS::CHUNK_MAT_MATERIAL:
// Add a new material to the list // Add a new material to the list
mScene->mMaterials.emplace_back(std::string("UNNAMED_" + ai_to_string(mScene->mMaterials.size()))); mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + to_string(mScene->mMaterials.size()))));
ParseMaterialChunk(); ParseMaterialChunk();
break; break;
@ -365,13 +368,13 @@ 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 be able to return valid cameras/lights even if no scenegraph is given. // to 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) {
case Discreet3DS::CHUNK_TRIMESH: { case Discreet3DS::CHUNK_TRIMESH: {
// this starts a new triangle mesh // this starts a new triangle mesh
mScene->mMeshes.emplace_back(std::string(name, num)); mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num)));
// Read mesh chunks // Read mesh chunks
ParseMeshChunk(); ParseMeshChunk();
@ -439,7 +442,7 @@ void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
// Read the lense angle // Read the lense angle
camera->mHorizontalFOV = AI_DEG_TO_RAD(stream->GetF4()); camera->mHorizontalFOV = AI_DEG_TO_RAD(stream->GetF4());
if (camera->mHorizontalFOV < 0.001f) { if (camera->mHorizontalFOV < 0.001f) {
camera->mHorizontalFOV = float(AI_DEG_TO_RAD(45.f)); camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f);
} }
// Now check for further subchunks // Now check for further subchunks
@ -924,7 +927,7 @@ void Discreet3DSImporter::ParseFaceChunk() {
} }
} }
if (0xcdcdcdcd == idx) { if (0xcdcdcdcd == idx) {
ASSIMP_LOG_ERROR("3DS: Unknown material: ", sz); ASSIMP_LOG_ERROR_F("3DS: Unknown material: ", sz);
} }
// Now continue and read all material indices // Now continue and read all material indices
@ -1000,7 +1003,7 @@ void Discreet3DSImporter::ParseMeshChunk() {
mMesh.mFaces.reserve(num); mMesh.mFaces.reserve(num);
while (num-- > 0) { while (num-- > 0) {
// 3DS faces are ALWAYS triangles // 3DS faces are ALWAYS triangles
mMesh.mFaces.emplace_back(); mMesh.mFaces.push_back(D3DS::Face());
D3DS::Face &sFace = mMesh.mFaces.back(); D3DS::Face &sFace = mMesh.mFaces.back();
sFace.mIndices[0] = (uint16_t)stream->GetI2(); sFace.mIndices[0] = (uint16_t)stream->GetI2();
@ -1285,7 +1288,7 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
switch (chunk.Flag) { switch (chunk.Flag) {
case Discreet3DS::CHUNK_LINRGBF: case Discreet3DS::CHUNK_LINRGBF:
bGamma = true; bGamma = true;
// fallthrough
case Discreet3DS::CHUNK_RGBF: case Discreet3DS::CHUNK_RGBF:
if (sizeof(float) * 3 > diff) { if (sizeof(float) * 3 > diff) {
*out = clrError; *out = clrError;
@ -1298,7 +1301,6 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
case Discreet3DS::CHUNK_LINRGBB: case Discreet3DS::CHUNK_LINRGBB:
bGamma = true; bGamma = true;
// fallthrough
case Discreet3DS::CHUNK_RGBB: { case Discreet3DS::CHUNK_RGBB: {
if (sizeof(char) * 3 > diff) { if (sizeof(char) * 3 > diff) {
*out = clrError; *out = clrError;
@ -1335,6 +1337,4 @@ 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

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -46,11 +46,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef AI_3DSIMPORTER_H_INC #ifndef AI_3DSIMPORTER_H_INC
#define AI_3DSIMPORTER_H_INC #define AI_3DSIMPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/types.h> #include <assimp/types.h>
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
#include "3DSHelper.h" #include "3DSHelper.h"
#include <assimp/StreamReader.h> #include <assimp/StreamReader.h>
@ -59,6 +59,7 @@ struct aiNode;
namespace Assimp { namespace Assimp {
using namespace D3DS; using namespace D3DS;
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -67,21 +68,21 @@ using namespace D3DS;
class Discreet3DSImporter : public BaseImporter { class Discreet3DSImporter : public BaseImporter {
public: public:
Discreet3DSImporter(); Discreet3DSImporter();
~Discreet3DSImporter() override = default; ~Discreet3DSImporter();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** 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;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ReadFile(). /** Called prior to ReadFile().
* The function is a request to the importer to update its configuration * The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
void SetupProperties(const Importer* pImp) override; void SetupProperties(const Importer* pImp);
protected: protected:
@ -89,14 +90,14 @@ protected:
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
*/ */
const aiImporterDesc* GetInfo () const override; const aiImporterDesc* GetInfo () const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Imports the given file into the given scene structure. /** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details * See BaseImporter::InternReadFile() for details
*/ */
void InternReadFile( const std::string& pFile, aiScene* pScene, void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler) override; IOSystem* pIOHandler);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Converts a temporary material to the outer representation /** Converts a temporary material to the outer representation
@ -207,15 +208,6 @@ protected:
*/ */
void ReplaceDefaultMaterial(); void ReplaceDefaultMaterial();
bool ContainsTextures(unsigned int i) const {
return !mScene->mMaterials[i].sTexDiffuse.mMapName.empty() ||
!mScene->mMaterials[i].sTexBump.mMapName.empty() ||
!mScene->mMaterials[i].sTexOpacity.mMapName.empty() ||
!mScene->mMaterials[i].sTexEmissive.mMapName.empty() ||
!mScene->mMaterials[i].sTexSpecular.mMapName.empty() ||
!mScene->mMaterials[i].sTexShininess.mMapName.empty() ;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Convert the whole scene /** Convert the whole scene
*/ */

View File

@ -1,179 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#pragma once
#include <assimp/vector3.h>
#include <assimp/matrix4x4.h>
#include <assimp/ParsingUtils.h>
#include <vector>
#include <string>
struct aiMaterial;
struct aiMesh;
namespace Assimp {
namespace D3MF {
enum class ResourceType {
RT_Object,
RT_BaseMaterials,
RT_EmbeddedTexture2D,
RT_Texture2DGroup,
RT_ColorGroup,
RT_Unknown
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
class Resource {
public:
int mId;
Resource(int id) :
mId(id) {
// empty
}
virtual ~Resource() = default;
virtual ResourceType getType() const {
return ResourceType::RT_Unknown;
}
};
class EmbeddedTexture : public Resource {
public:
std::string mPath;
std::string mContentType;
std::string mTilestyleU;
std::string mTilestyleV;
std::vector<char> mBuffer;
EmbeddedTexture(int id) :
Resource(id),
mPath(),
mContentType(),
mTilestyleU(),
mTilestyleV() {
// empty
}
~EmbeddedTexture() override = default;
ResourceType getType() const override {
return ResourceType::RT_EmbeddedTexture2D;
}
};
class Texture2DGroup : public Resource {
public:
std::vector<aiVector2D> mTex2dCoords;
int mTexId;
Texture2DGroup(int id) :
Resource(id),
mTexId(-1) {
// empty
}
~Texture2DGroup() override = default;
ResourceType getType() const override {
return ResourceType::RT_Texture2DGroup;
}
};
class ColorGroup : public Resource {
public:
std::vector<aiColor4D> mColors;
ColorGroup(int id) :
Resource(id){
// empty
}
~ColorGroup() override = default;
ResourceType getType() const override {
return ResourceType::RT_ColorGroup;
}
};
class BaseMaterials : public Resource {
public:
std::vector<unsigned int> mMaterialIndex;
BaseMaterials(int id) :
Resource(id),
mMaterialIndex() {
// empty
}
~BaseMaterials() override = default;
ResourceType getType() const override {
return ResourceType::RT_BaseMaterials;
}
};
struct Component {
int mObjectId;
aiMatrix4x4 mTransformation;
};
class Object : public Resource {
public:
std::vector<aiMesh *> mMeshes;
std::vector<unsigned int> mMeshIndex;
std::vector<Component> mComponents;
std::string mName;
Object(int id) :
Resource(id),
mName(std::string("Object_") + ai_to_string(id)) {
// empty
}
~Object() override = default;
ResourceType getType() const override {
return ResourceType::RT_Object;
}
};
} // namespace D3MF
} // namespace Assimp

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -44,80 +45,59 @@ namespace Assimp {
namespace D3MF { namespace D3MF {
namespace XmlTag { namespace XmlTag {
// Root tag
const char* const RootTag = "3MF";
// Meta-data // Meta-data
const char* const meta = "metadata"; static const std::string meta = "metadata";
const char* const meta_name = "name"; static const std::string meta_name = "name";
// Model-data specific tags // Model-data specific tags
const char* const model = "model"; static const std::string model = "model";
const char* const model_unit = "unit"; static const std::string model_unit = "unit";
const char* const metadata = "metadata"; static const std::string metadata = "metadata";
const char* const resources = "resources"; static const std::string resources = "resources";
const char* const object = "object"; static const std::string object = "object";
const char* const mesh = "mesh"; static const std::string mesh = "mesh";
const char* const components = "components"; static const std::string vertices = "vertices";
const char* const component = "component"; static const std::string vertex = "vertex";
const char* const vertices = "vertices"; static const std::string triangles = "triangles";
const char* const vertex = "vertex"; static const std::string triangle = "triangle";
const char* const triangles = "triangles"; static const std::string x = "x";
const char* const triangle = "triangle"; static const std::string y = "y";
const char* const x = "x"; static const std::string z = "z";
const char* const y = "y"; static const std::string v1 = "v1";
const char* const z = "z"; static const std::string v2 = "v2";
const char* const v1 = "v1"; static const std::string v3 = "v3";
const char* const v2 = "v2"; static const std::string id = "id";
const char* const v3 = "v3"; static const std::string pid = "pid";
const char* const id = "id"; static const std::string p1 = "p1";
const char* const pid = "pid"; static const std::string name = "name";
const char* const pindex = "pindex"; static const std::string type = "type";
const char* const p1 = "p1"; static const std::string build = "build";
const char *const p2 = "p2"; static const std::string item = "item";
const char *const p3 = "p3"; static const std::string objectid = "objectid";
const char* const name = "name"; static const std::string transform = "transform";
const char* const type = "type";
const char* const build = "build";
const char* const item = "item";
const char* const objectid = "objectid";
const char* const transform = "transform";
const char *const path = "path";
// Material definitions // Material definitions
const char* const basematerials = "basematerials"; static const std::string basematerials = "basematerials";
const char* const basematerials_base = "base"; static const std::string basematerials_id = "id";
const char* const basematerials_name = "name"; static const std::string basematerials_base = "base";
const char* const basematerials_displaycolor = "displaycolor"; static const std::string basematerials_name = "name";
const char* const texture_2d = "m:texture2d"; static const std::string basematerials_displaycolor = "displaycolor";
const char *const texture_group = "m:texture2dgroup";
const char *const texture_content_type = "contenttype";
const char *const texture_tilestyleu = "tilestyleu";
const char *const texture_tilestylev = "tilestylev";
const char *const texture_2d_coord = "m:tex2coord";
const char *const texture_cuurd_u = "u";
const char *const texture_cuurd_v = "v";
// vertex color definitions
const char *const colorgroup = "m:colorgroup";
const char *const color_item = "m:color";
const char *const color_vaule = "color";
// Meta info tags // Meta info tags
const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml"; static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels"; static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
const char* const SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types"; static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
const char* const SCHEMA_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships"; static const std::string SCHEMA_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
const char* const RELS_RELATIONSHIP_CONTAINER = "Relationships"; static const std::string RELS_RELATIONSHIP_CONTAINER = "Relationships";
const char* const RELS_RELATIONSHIP_NODE = "Relationship"; static const std::string RELS_RELATIONSHIP_NODE = "Relationship";
const char* const RELS_ATTRIB_TARGET = "Target"; static const std::string RELS_ATTRIB_TARGET = "Target";
const char* const RELS_ATTRIB_TYPE = "Type"; static const std::string RELS_ATTRIB_TYPE = "Type";
const char* const RELS_ATTRIB_ID = "Id"; static const std::string RELS_ATTRIB_ID = "Id";
const char* const PACKAGE_START_PART_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel"; static const std::string PACKAGE_START_PART_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
const char* const PACKAGE_PRINT_TICKET_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket"; static const std::string PACKAGE_PRINT_TICKET_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket";
const char* const PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture"; static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
const char* const PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
const char* const PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"; static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
} }
} // Namespace D3MF } // Namespace D3MF

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -83,7 +84,7 @@ void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScen
namespace D3MF { namespace D3MF {
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) : D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene) { mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
// empty // empty
} }
@ -137,7 +138,7 @@ bool D3MFExporter::exportContentTypes() {
mContentOutput << std::endl; mContentOutput << std::endl;
mContentOutput << "</Types>"; mContentOutput << "</Types>";
mContentOutput << std::endl; mContentOutput << std::endl;
zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE); exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
return true; return true;
} }
@ -162,7 +163,7 @@ bool D3MFExporter::exportRelations() {
mRelOutput << "</Relationships>"; mRelOutput << "</Relationships>";
mRelOutput << std::endl; mRelOutput << std::endl;
zipRelInfo("_rels", ".rels"); writeRelInfoToFile("_rels", ".rels");
mRelOutput.flush(); mRelOutput.flush();
return true; return true;
@ -196,7 +197,7 @@ bool D3MFExporter::export3DModel() {
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
mRelations.push_back(info); mRelations.push_back(info);
zipModel("3D", "3DModel.model"); writeModelToArchive("3D", "3DModel.model");
mModelOutput.flush(); mModelOutput.flush();
return true; return true;
@ -237,7 +238,7 @@ void D3MFExporter::writeBaseMaterials() {
aiMaterial *mat = mScene->mMaterials[i]; aiMaterial *mat = mScene->mMaterials[i];
aiString name; aiString name;
if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) { if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
strName = "basemat_" + ai_to_string(i); strName = "basemat_" + to_string(i);
} else { } else {
strName = name.C_Str(); strName = name.C_Str();
} }
@ -248,22 +249,22 @@ void D3MFExporter::writeBaseMaterials() {
// rgbs % // rgbs %
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) { if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
hexDiffuseColor = ai_rgba2hex( hexDiffuseColor = Rgba2Hex(
(int)(((ai_real)color.r) * 255), (int)((ai_real)color.r) * 255,
(int)(((ai_real)color.g) * 255), (int)((ai_real)color.g) * 255,
(int)(((ai_real)color.b) * 255), (int)((ai_real)color.b) * 255,
(int)(((ai_real)color.a) * 255), (int)((ai_real)color.a) * 255,
true); true);
} else { } else {
hexDiffuseColor = "#"; hexDiffuseColor = "#";
tmp = ai_decimal_to_hexa((ai_real)color.r); tmp = DecimalToHexa((ai_real)color.r);
hexDiffuseColor += tmp; hexDiffuseColor += tmp;
tmp = ai_decimal_to_hexa((ai_real)color.g); tmp = DecimalToHexa((ai_real)color.g);
hexDiffuseColor += tmp; hexDiffuseColor += tmp;
tmp = ai_decimal_to_hexa((ai_real)color.b); tmp = DecimalToHexa((ai_real)color.b);
hexDiffuseColor += tmp; hexDiffuseColor += tmp;
tmp = ai_decimal_to_hexa((ai_real)color.a); tmp = DecimalToHexa((ai_real)color.a);
hexDiffuseColor += tmp; hexDiffuseColor += tmp;
} }
} else { } else {
@ -307,26 +308,18 @@ void D3MFExporter::writeMesh(aiMesh *mesh) {
return; return;
} }
mModelOutput << "<" mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
<< XmlTag::mesh mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
<< ">" << "\n";
mModelOutput << "<"
<< XmlTag::vertices
<< ">" << "\n";
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
writeVertex(mesh->mVertices[i]); writeVertex(mesh->mVertices[i]);
} }
mModelOutput << "</" mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
<< XmlTag::vertices << ">"
<< "\n";
const unsigned int matIdx(mesh->mMaterialIndex); const unsigned int matIdx(mesh->mMaterialIndex);
writeFaces(mesh, matIdx); writeFaces(mesh, matIdx);
mModelOutput << "</" mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
<< XmlTag::mesh << ">"
<< "\n";
} }
void D3MFExporter::writeVertex(const aiVector3D &pos) { void D3MFExporter::writeVertex(const aiVector3D &pos) {
@ -342,57 +335,65 @@ void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
if (!mesh->HasFaces()) { if (!mesh->HasFaces()) {
return; return;
} }
mModelOutput << "<" mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
<< XmlTag::triangles << ">"
<< "\n";
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
aiFace &currentFace = mesh->mFaces[i]; aiFace &currentFace = mesh->mFaces[i];
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\"" mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
<< currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2] << currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
<< "\" pid=\"1\" p1=\"" + ai_to_string(matIdx) + "\" />"; << "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />";
mModelOutput << "\n"; mModelOutput << std::endl;
} }
mModelOutput << "</" mModelOutput << "</" << XmlTag::triangles << ">";
<< XmlTag::triangles mModelOutput << std::endl;
<< ">";
mModelOutput << "\n";
} }
void D3MFExporter::writeBuild() { void D3MFExporter::writeBuild() {
mModelOutput << "<" mModelOutput << "<" << XmlTag::build << ">" << std::endl;
<< XmlTag::build
<< ">"
<< "\n";
for (size_t i = 0; i < mBuildItems.size(); ++i) { for (size_t i = 0; i < mBuildItems.size(); ++i) {
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>"; mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
mModelOutput << "\n"; mModelOutput << std::endl;
} }
mModelOutput << "</" << XmlTag::build << ">"; mModelOutput << "</" << XmlTag::build << ">";
mModelOutput << "\n"; mModelOutput << std::endl;
} }
void D3MFExporter::zipContentType(const std::string &filename) { void D3MFExporter::exportContentTyp(const std::string &filename) {
addFileInZip(filename, mContentOutput.str());
}
void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) {
const std::string entry = folder + "/" + modelName;
addFileInZip(entry, mModelOutput.str());
}
void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) {
const std::string entry = folder + "/" + relName;
addFileInZip(entry, mRelOutput.str());
}
void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) {
if (nullptr == m_zipArchive) { if (nullptr == m_zipArchive) {
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
} }
const std::string entry = filename;
zip_entry_open(m_zipArchive, entry.c_str()); zip_entry_open(m_zipArchive, entry.c_str());
zip_entry_write(m_zipArchive, content.c_str(), content.size());
const std::string &exportTxt(mContentOutput.str());
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
zip_entry_close(m_zipArchive);
}
void D3MFExporter::writeModelToArchive(const std::string &folder, const std::string &modelName) {
if (nullptr == m_zipArchive) {
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
}
const std::string entry = folder + "/" + modelName;
zip_entry_open(m_zipArchive, entry.c_str());
const std::string &exportTxt(mModelOutput.str());
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
zip_entry_close(m_zipArchive);
}
void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) {
if (nullptr == m_zipArchive) {
throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
}
const std::string entry = folder + "/" + relName;
zip_entry_open(m_zipArchive, entry.c_str());
const std::string &exportTxt(mRelOutput.str());
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
zip_entry_close(m_zipArchive); zip_entry_close(m_zipArchive);
} }

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -40,9 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#pragma once #pragma once
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -61,6 +59,8 @@ class IOStream;
namespace D3MF { namespace D3MF {
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
struct OpcPackageRelationship; struct OpcPackageRelationship;
@ -83,12 +83,9 @@ protected:
void writeVertex( const aiVector3D &pos ); void writeVertex( const aiVector3D &pos );
void writeFaces( aiMesh *mesh, unsigned int matIdx ); void writeFaces( aiMesh *mesh, unsigned int matIdx );
void writeBuild(); void writeBuild();
void exportContentTyp( const std::string &filename );
// Zip the data void writeModelToArchive( const std::string &folder, const std::string &modelName );
void zipContentType( const std::string &filename ); void writeRelInfoToFile( const std::string &folder, const std::string &relName );
void zipModel( const std::string &folder, const std::string &modelName );
void zipRelInfo( const std::string &folder, const std::string &relName );
void addFileInZip( const std::string &entry, const std::string &content );
private: private:
std::string mArchiveName; std::string mArchiveName;
@ -101,11 +98,9 @@ private:
std::vector<OpcPackageRelationship*> mRelations; std::vector<OpcPackageRelationship*> mRelations;
}; };
#endif // ASSIMP_BUILD_NO_3MF_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT
} // Namespace D3MF } // Namespace D3MF
} // Namespace Assimp } // Namespace Assimp
#endif // ASSIMP_BUILD_NO_3MF_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,33 +43,381 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#include "D3MFImporter.h" #include "D3MFImporter.h"
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include "XmlSerializer.h"
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/fast_atof.h>
#include <cassert> #include <cassert>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h>
#include <assimp/irrXMLWrapper.h>
#include <iomanip> #include <iomanip>
#include <cstring>
namespace Assimp { namespace Assimp {
namespace D3MF {
using namespace D3MF; class XmlSerializer {
public:
using MatArray = std::vector<aiMaterial *>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
static constexpr aiImporterDesc desc = { XmlSerializer(XmlReader *xmlReader) :
mMeshes(),
mMatArray(),
mActiveMatGroup(99999999),
mMatId2MatArray(),
xmlReader(xmlReader) {
// empty
}
~XmlSerializer() {
// empty
}
void ImportXml(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mRootNode = new aiNode();
std::vector<aiNode *> children;
std::string nodeName;
while (ReadToEndElement(D3MF::XmlTag::model)) {
nodeName = xmlReader->getNodeName();
if (nodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(scene));
} else if (nodeName == D3MF::XmlTag::build) {
//
} else if (nodeName == D3MF::XmlTag::basematerials) {
ReadBaseMaterials();
} else if (nodeName == D3MF::XmlTag::meta) {
ReadMetadata();
}
}
if (scene->mRootNode->mName.length == 0) {
scene->mRootNode->mName.Set("3MF");
}
// import the metadata
if (!mMetaData.empty()) {
const size_t numMeta(mMetaData.size());
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
for (size_t i = 0; i < numMeta; ++i) {
aiString val(mMetaData[i].value);
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes);
// import the materials
scene->mNumMaterials = static_cast<unsigned int>(mMatArray.size());
if (0 != scene->mNumMaterials) {
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
}
// create the scenegraph
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
}
private:
aiNode *ReadObject(aiScene *scene) {
std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds;
const char *attrib(nullptr);
std::string name, type;
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
if (nullptr != attrib) {
name = attrib;
}
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
if (nullptr != attrib) {
type = attrib;
}
node->mParent = scene->mRootNode;
node->mName.Set(name);
size_t meshIdx = mMeshes.size();
while (ReadToEndElement(D3MF::XmlTag::object)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh();
mesh->mName.Set(name);
mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx));
++meshIdx;
}
}
node->mNumMeshes = static_cast<unsigned int>(meshIds.size());
node->mMeshes = new unsigned int[node->mNumMeshes];
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
return node.release();
}
aiMesh *ReadMesh() {
aiMesh *mesh = new aiMesh();
while (ReadToEndElement(D3MF::XmlTag::mesh)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
ImportVertices(mesh);
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
ImportTriangles(mesh);
}
}
return mesh;
}
void ReadMetadata() {
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
xmlReader->read();
const std::string value = xmlReader->getNodeData();
if (name.empty()) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back(entry);
}
void ImportVertices(aiMesh *mesh) {
std::vector<aiVector3D> vertices;
while (ReadToEndElement(D3MF::XmlTag::vertices)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex());
}
}
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
aiVector3D ReadVertex() {
aiVector3D vertex;
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr);
vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr);
return vertex;
}
void ImportTriangles(aiMesh *mesh) {
std::vector<aiFace> faces;
while (ReadToEndElement(D3MF::XmlTag::triangles)) {
const std::string nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
faces.push_back(ReadTriangle());
const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
if (nullptr != pidToken) {
int matIdx(std::atoi(pidToken));
mesh->mMaterialIndex = matIdx;
}
}
}
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
aiFace ReadTriangle() {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str())));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str())));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str())));
return face;
}
void ReadBaseMaterials() {
std::vector<unsigned int> MatIdArray;
const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str()));
if (nullptr != baseMaterialId) {
unsigned int id = std::atoi(baseMaterialId);
const size_t newMatIdx(mMatArray.size());
if (id != mActiveMatGroup) {
mActiveMatGroup = id;
MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
if (mMatId2MatArray.end() == it) {
MatIdArray.clear();
mMatId2MatArray[id] = MatIdArray;
} else {
MatIdArray = it->second;
}
}
MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
mMatId2MatArray[mActiveMatGroup] = MatIdArray;
}
while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
mMatArray.push_back(readMaterialDef());
}
}
bool parseColor(const char *color, aiColor4D &diffuse) {
if (nullptr == color) {
return false;
}
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
const size_t len(strlen(color));
if (9 != len && 7 != len) {
return false;
}
const char *buf(color);
if ('#' != *buf) {
return false;
}
++buf;
char comp[3] = { 0, 0, '\0' };
comp[0] = *buf;
++buf;
comp[1] = *buf;
++buf;
diffuse.r = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
comp[0] = *buf;
++buf;
comp[1] = *buf;
++buf;
diffuse.g = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
comp[0] = *buf;
++buf;
comp[1] = *buf;
++buf;
diffuse.b = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
if (7 == len)
return true;
comp[0] = *buf;
++buf;
comp[1] = *buf;
++buf;
diffuse.a = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
return true;
}
void assignDiffuseColor(aiMaterial *mat) {
const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
aiColor4D diffuse;
if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
}
}
aiMaterial *readMaterialDef() {
aiMaterial *mat(nullptr);
const char *name(nullptr);
const std::string nodeName(xmlReader->getNodeName());
if (nodeName == D3MF::XmlTag::basematerials_base) {
name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str());
std::string stdMatName;
aiString matName;
std::string strId(to_string(mActiveMatGroup));
stdMatName += "id";
stdMatName += strId;
stdMatName += "_";
if (nullptr != name) {
stdMatName += std::string(name);
} else {
stdMatName += "basemat";
}
matName.Set(stdMatName);
mat = new aiMaterial;
mat->AddProperty(&matName, AI_MATKEY_NAME);
assignDiffuseColor(mat);
}
return mat;
}
private:
bool ReadToStartElement(const std::string &startTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
return false;
}
bool ReadToEndElement(const std::string &closeTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false;
}
}
ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
private:
struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::vector<aiMesh *> mMeshes;
MatArray mMatArray;
unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray;
XmlReader *xmlReader;
};
} //namespace D3MF
static const aiImporterDesc desc = {
"3mf Importer", "3mf Importer",
"", "",
"", "",
@ -81,20 +430,34 @@ static constexpr aiImporterDesc desc = {
"3mf" "3mf"
}; };
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool ) const { D3MFImporter::D3MFImporter() :
BaseImporter() {
// empty
}
D3MFImporter::~D3MFImporter() {
// empty
}
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension(GetExtension(filename));
if (extension == desc.mFileExtensions) {
return true;
} else if (!extension.length() || checkSig) {
if (nullptr == pIOHandler) {
return false;
}
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false; return false;
} }
static const char *const ModelRef = "3D/3dmodel.model"; D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
ZipArchiveIOSystem archive(pIOHandler, filename); return opcPackage.validate();
if (!archive.Exists(ModelRef)) {
return false;
} }
return true; return false;
} }
void D3MFImporter::SetupProperties(const Importer*) { void D3MFImporter::SetupProperties(const Importer * /*pImp*/) {
// empty // empty
} }
@ -103,22 +466,14 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
} }
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) { void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
D3MFOpcPackage opcPackage(pIOHandler, filename); D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
D3MF::XmlSerializer xmlSerializer(xmlReader.get());
XmlParser xmlParser;
if (xmlParser.parse(opcPackage.RootStream())) {
XmlSerializer xmlSerializer(&xmlParser);
xmlSerializer.ImportXml(pScene); xmlSerializer.ImportXml(pScene);
const std::vector<aiTexture*> &tex = opcPackage.GetEmbeddedTextures();
if (!tex.empty()) {
pScene->mNumTextures = static_cast<unsigned int>(tex.size());
pScene->mTextures = new aiTexture *[pScene->mNumTextures];
for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {
pScene->mTextures[i] = tex[i];
}
}
}
} }
} // Namespace Assimp } // Namespace Assimp

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,50 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_D3MFLOADER_H_INCLUDED #ifndef AI_D3MFLOADER_H_INCLUDED
#define AI_D3MFLOADER_H_INCLUDED #define AI_D3MFLOADER_H_INCLUDED
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
namespace Assimp { namespace Assimp {
// ---------------------------------------------------------------------------
/// @brief The 3MF-importer class.
///
/// Implements the basic topology import and embedded textures.
// ---------------------------------------------------------------------------
class D3MFImporter : public BaseImporter { class D3MFImporter : public BaseImporter {
public: public:
/// @brief The default class constructor. // BaseImporter interface
D3MFImporter() = default; D3MFImporter();
~D3MFImporter();
/// @brief The class destructor. bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
~D3MFImporter() override = default; void SetupProperties(const Importer *pImp);
const aiImporterDesc *GetInfo() const;
/// @brief Performs the data format detection.
/// @param pFile The filename to check.
/// @param pIOHandler The used IO-System.
/// @param checkSig true for signature checking.
/// @return true for can be loaded, false for not.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
/// @brief Not used
/// @param pImp Not used
void SetupProperties(const Importer *pImp) override;
/// @brief The importer description getter.
/// @return The info
const aiImporterDesc *GetInfo() const override;
protected: protected:
/// @brief Internal read function, performs the file parsing. void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
/// @param pFile The filename
/// @param pScene The scene to load in.
/// @param pIOHandler The io-system
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
}; };
} // Namespace Assimp } // Namespace Assimp
#endif // #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#endif // AI_D3MFLOADER_H_INCLUDED #endif // AI_D3MFLOADER_H_INCLUDED

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -43,19 +44,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/texture.h>
#include "3MFXmlTags.h"
#include "3MFXmlTags.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <map> #include <map>
#include <memory>
#include <vector> #include <vector>
namespace Assimp { namespace Assimp {
@ -63,27 +64,31 @@ namespace Assimp {
namespace D3MF { namespace D3MF {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
using OpcPackageRelationshipPtr = std::shared_ptr<OpcPackageRelationship>; typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
class OpcPackageRelationshipReader { class OpcPackageRelationshipReader {
public: public:
OpcPackageRelationshipReader(XmlParser &parser) : OpcPackageRelationshipReader(XmlReader *xmlReader) {
mRelations() { while (xmlReader->read()) {
XmlNode root = parser.getRootNode(); if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
ParseRootNode(root); xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) {
} ParseRootNode(xmlReader);
void ParseRootNode(XmlNode &node) {
ParseAttributes(node);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
std::string name = currentNode.name();
if (name == "Relationships") {
ParseRelationsNode(currentNode);
} }
} }
} }
void ParseAttributes(XmlNode & /*node*/) { void ParseRootNode(XmlReader *xmlReader) {
ParseAttributes(xmlReader);
while (xmlReader->read()) {
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
ParseChildNode(xmlReader);
}
}
}
void ParseAttributes(XmlReader *) {
// empty // empty
} }
@ -91,51 +96,29 @@ public:
if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) { if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) {
return false; return false;
} }
return true; return true;
} }
void ParseRelationsNode(XmlNode &node) { void ParseChildNode(XmlReader *xmlReader) {
if (node.empty()) {
return;
}
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string name = currentNode.name();
if (name == "Relationship") {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID).as_string();
relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE).as_string(); relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str());
relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET).as_string(); relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str());
relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str());
if (validateRels(relPtr)) { if (validateRels(relPtr)) {
mRelations.push_back(relPtr); m_relationShips.push_back(relPtr);
}
}
} }
} }
std::vector<OpcPackageRelationshipPtr> mRelations; std::vector<OpcPackageRelationshipPtr> m_relationShips;
}; };
static bool IsEmbeddedTexture( const std::string &filename ) {
const std::string extension = BaseImporter::GetExtension(filename);
if (extension == "jpg" || extension == "png" || extension == "jpeg") {
std::string::size_type pos = filename.find("thumbnail");
if (pos != std::string::npos) {
return false;
}
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr), mRootStream(nullptr), mZipArchive() {
mZipArchive() { mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
mZipArchive = new ZipArchiveIOSystem(pIOHandler, rFile);
if (!mZipArchive->isOpen()) { if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file ", rFile, "."); throw DeadlyImportError("Failed to open file " + rFile + ".");
} }
std::vector<std::string> fileList; std::vector<std::string> fileList;
@ -149,12 +132,12 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
IOStream *fileStream = mZipArchive->Open(file.c_str()); IOStream *fileStream = mZipArchive->Open(file.c_str());
if (nullptr == fileStream) { if (nullptr == fileStream) {
ASSIMP_LOG_ERROR("Filestream is nullptr."); ai_assert(fileStream != nullptr);
continue; continue;
} }
std::string rootFile = ReadPackageRootRelationship(fileStream); std::string rootFile = ReadPackageRootRelationship(fileStream);
if (!rootFile.empty() && rootFile[0] == '/') { if (rootFile.size() > 0 && rootFile[0] == '/') {
rootFile = rootFile.substr(1); rootFile = rootFile.substr(1);
if (rootFile[0] == '/') { if (rootFile[0] == '/') {
// deal with zip-bug // deal with zip-bug
@ -169,87 +152,52 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream = mZipArchive->Open(rootFile.c_str()); mRootStream = mZipArchive->Open(rootFile.c_str());
ai_assert(mRootStream != nullptr); ai_assert(mRootStream != nullptr);
if (nullptr == mRootStream) { if (nullptr == mRootStream) {
throw DeadlyImportError("Cannot open root-file in archive : " + rootFile); throw DeadlyExportError("Cannot open root-file in archive : " + rootFile);
} }
} else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file); ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file);
} else if (IsEmbeddedTexture(file)) {
IOStream *fileStream = mZipArchive->Open(file.c_str());
LoadEmbeddedTextures(fileStream, file);
mZipArchive->Close(fileStream);
} else { } else {
ASSIMP_LOG_WARN("Ignored file of unknown type: ", file); ASSIMP_LOG_WARN_F("Ignored file of unknown type: ", file);
} }
} }
} }
D3MFOpcPackage::~D3MFOpcPackage() { D3MFOpcPackage::~D3MFOpcPackage() {
mZipArchive->Close(mRootStream); mZipArchive->Close(mRootStream);
delete mZipArchive;
} }
IOStream *D3MFOpcPackage::RootStream() const { IOStream *D3MFOpcPackage::RootStream() const {
return mRootStream; return mRootStream;
} }
const std::vector<aiTexture *> &D3MFOpcPackage::GetEmbeddedTextures() const { static const std::string ModelRef = "3D/3dmodel.model";
return mEmbeddedTextures;
}
static const char *const ModelRef = "3D/3dmodel.model";
bool D3MFOpcPackage::validate() { bool D3MFOpcPackage::validate() {
if (nullptr == mRootStream || nullptr == mZipArchive) { if (nullptr == mRootStream || nullptr == mZipArchive) {
return false; return false;
} }
return mZipArchive->Exists(ModelRef); return mZipArchive->Exists(ModelRef.c_str());
} }
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
XmlParser xmlParser; std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
if (!xmlParser.parse(stream)) { std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
return std::string();
}
OpcPackageRelationshipReader reader(xmlParser); OpcPackageRelationshipReader reader(xml.get());
auto itr = std::find_if(reader.mRelations.begin(), reader.mRelations.end(), [](const OpcPackageRelationshipPtr &rel) { auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.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.mRelations.end()) { if (itr == reader.m_relationShips.end()) {
throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
} }
return (*itr)->target; return (*itr)->target;
} }
void D3MFOpcPackage::LoadEmbeddedTextures(IOStream *fileStream, const std::string &filename) {
if (nullptr == fileStream) {
return;
}
const size_t size = fileStream->FileSize();
if (0 == size) {
return;
}
unsigned char *data = new unsigned char[size];
fileStream->Read(data, 1, size);
aiTexture *texture = new aiTexture;
std::string embName = "*" + filename;
texture->mFilename.Set(embName.c_str());
texture->mWidth = static_cast<unsigned int>(size);
texture->mHeight = 0;
texture->achFormatHint[0] = 'p';
texture->achFormatHint[1] = 'n';
texture->achFormatHint[2] = 'g';
texture->achFormatHint[3] = '\0';
texture->pcData = (aiTexel*) data;
mEmbeddedTextures.emplace_back(texture);
}
} // Namespace D3MF } // Namespace D3MF
} // Namespace Assimp } // Namespace Assimp

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,18 +43,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef D3MFOPCPACKAGE_H #ifndef D3MFOPCPACKAGE_H
#define D3MFOPCPACKAGE_H #define D3MFOPCPACKAGE_H
#include <assimp/IOSystem.hpp>
#include <memory> #include <memory>
#include <string>
struct aiTexture; #include <assimp/IOSystem.hpp>
#include <assimp/irrXMLWrapper.h>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ;
using XmlReaderPtr = std::shared_ptr<XmlReader> ;
struct OpcPackageRelationship { struct OpcPackageRelationship {
std::string id; std::string id;
std::string type; std::string type;
@ -62,23 +64,20 @@ struct OpcPackageRelationship {
class D3MFOpcPackage { class D3MFOpcPackage {
public: public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& file ); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate(); bool validate();
const std::vector<aiTexture*> &GetEmbeddedTextures() const;
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
void LoadEmbeddedTextures(IOStream *fileStream, const std::string &filename);
private: private:
IOStream* mRootStream; IOStream* mRootStream;
ZipArchiveIOSystem *mZipArchive; std::unique_ptr<ZipArchiveIOSystem> mZipArchive;
std::vector<aiTexture *> mEmbeddedTextures;
}; };
} // namespace D3MF } // Namespace D3MF
} // namespace Assimp } // Namespace Assimp
#endif // D3MFOPCPACKAGE_H #endif // D3MFOPCPACKAGE_H

View File

@ -1,724 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#include "XmlSerializer.h"
#include "D3MFOpcPackage.h"
#include "3MFXmlTags.h"
#include "3MFTypes.h"
#include <assimp/scene.h>
#include <utility>
namespace Assimp {
namespace D3MF {
static constexpr int IdNotSet = -1;
namespace {
static constexpr size_t ColRGBA_Len = 9;
static constexpr size_t ColRGB_Len = 7;
// format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
bool validateColorString(const std::string color) {
const size_t len = color.size();
if (ColRGBA_Len != len && ColRGB_Len != len) {
return false;
}
return true;
}
aiFace ReadTriangle(XmlNode &node, int &texId0, int &texId1, int &texId2) {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v1).as_string()));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
texId0 = texId1 = texId2 = IdNotSet;
XmlParser::getIntAttribute(node, XmlTag::p1, texId0);
XmlParser::getIntAttribute(node, XmlTag::p2, texId1);
XmlParser::getIntAttribute(node, XmlTag::p3, texId2);
return face;
}
aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(XmlTag::x).as_string(), nullptr);
vertex.y = ai_strtof(node.attribute(XmlTag::y).as_string(), nullptr);
vertex.z = ai_strtof(node.attribute(XmlTag::z).as_string(), nullptr);
return vertex;
}
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, std::string &value) {
pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str());
if (!objectAttribute.empty()) {
value = objectAttribute.as_string();
return true;
}
return false;
}
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
std::string strValue;
const bool ret = getNodeAttribute(node, attribute, strValue);
if (ret) {
value = std::atoi(strValue.c_str());
return true;
}
return false;
}
aiMatrix4x4 parseTransformMatrix(const std::string& matrixStr) {
// split the string
std::vector<float> numbers;
std::string currentNumber;
for (char c : matrixStr) {
if (c == ' ') {
if (!currentNumber.empty()) {
float f = std::stof(currentNumber);
numbers.push_back(f);
currentNumber.clear();
}
} else {
currentNumber.push_back(c);
}
}
if (!currentNumber.empty()) {
const float f = std::stof(currentNumber);
numbers.push_back(f);
}
aiMatrix4x4 transformMatrix;
transformMatrix.a1 = numbers[0];
transformMatrix.b1 = numbers[1];
transformMatrix.c1 = numbers[2];
transformMatrix.d1 = 0;
transformMatrix.a2 = numbers[3];
transformMatrix.b2 = numbers[4];
transformMatrix.c2 = numbers[5];
transformMatrix.d2 = 0;
transformMatrix.a3 = numbers[6];
transformMatrix.b3 = numbers[7];
transformMatrix.c3 = numbers[8];
transformMatrix.d3 = 0;
transformMatrix.a4 = numbers[9];
transformMatrix.b4 = numbers[10];
transformMatrix.c4 = numbers[11];
transformMatrix.d4 = 1;
return transformMatrix;
}
bool parseColor(const std::string &color, aiColor4D &diffuse) {
if (color.empty()) {
return false;
}
if (!validateColorString(color)) {
return false;
}
if ('#' != color[0]) {
return false;
}
char r[3] = { color[1], color[2], '\0' };
diffuse.r = static_cast<ai_real>(strtol(r, nullptr, 16)) / ai_real(255.0);
char g[3] = { color[3], color[4], '\0' };
diffuse.g = static_cast<ai_real>(strtol(g, nullptr, 16)) / ai_real(255.0);
char b[3] = { color[5], color[6], '\0' };
diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
const size_t len = color.size();
if (ColRGB_Len == len) {
return true;
}
char a[3] = { color[7], color[8], '\0' };
diffuse.a = static_cast<ai_real>(strtol(a, nullptr, 16)) / ai_real(255.0);
return true;
}
void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
const char *color = node.attribute(XmlTag::basematerials_displaycolor).as_string();
aiColor4D diffuse;
if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
}
}
} // namespace
XmlSerializer::XmlSerializer(XmlParser *xmlParser) :
mResourcesDictionnary(),
mMeshCount(0),
mXmlParser(xmlParser) {
ai_assert(nullptr != xmlParser);
}
XmlSerializer::~XmlSerializer() {
for (auto &it : mResourcesDictionnary) {
delete it.second;
}
}
void XmlSerializer::ImportXml(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mRootNode = new aiNode(XmlTag::RootTag);
XmlNode node = mXmlParser->getRootNode().child(XmlTag::model);
if (node.empty()) {
return;
}
XmlNode resNode = node.child(XmlTag::resources);
for (auto &currentNode : resNode.children()) {
const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::texture_2d) {
ReadEmbeddecTexture(currentNode);
} else if (currentNodeName == XmlTag::texture_group) {
ReadTextureGroup(currentNode);
} else if (currentNodeName == XmlTag::object) {
ReadObject(currentNode);
} else if (currentNodeName == XmlTag::basematerials) {
ReadBaseMaterials(currentNode);
} else if (currentNodeName == XmlTag::meta) {
ReadMetadata(currentNode);
} else if (currentNodeName == XmlTag::colorgroup) {
ReadColorGroup(currentNode);
}
}
StoreMaterialsInScene(scene);
XmlNode buildNode = node.child(XmlTag::build);
if (buildNode.empty()) {
return;
}
for (auto &currentNode : buildNode.children()) {
const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::item) {
int objectId = IdNotSet;
std::string transformationMatrixStr;
aiMatrix4x4 transformationMatrix;
getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId);
bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr);
auto it = mResourcesDictionnary.find(objectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it->second);
if (hasTransform) {
transformationMatrix = parseTransformMatrix(transformationMatrixStr);
}
addObjectToNode(scene->mRootNode, obj, transformationMatrix);
}
}
}
// import the metadata
if (!mMetaData.empty()) {
const size_t numMeta = mMetaData.size();
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
for (size_t i = 0; i < numMeta; ++i) {
aiString val(mMetaData[i].value);
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
}
}
// import the meshes, materials are already stored
scene->mNumMeshes = static_cast<unsigned int>(mMeshCount);
if (scene->mNumMeshes != 0) {
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
for (auto &it : mResourcesDictionnary) {
if (it.second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it.second);
ai_assert(nullptr != obj);
for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
}
}
}
}
}
void XmlSerializer::addObjectToNode(aiNode *parent, Object *obj, aiMatrix4x4 nodeTransform) {
ai_assert(nullptr != obj);
aiNode *sceneNode = new aiNode(obj->mName);
sceneNode->mNumMeshes = static_cast<unsigned int>(obj->mMeshes.size());
sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes);
sceneNode->mTransformation = nodeTransform;
if (nullptr != parent) {
parent->addChildren(1, &sceneNode);
}
for (Assimp::D3MF::Component c : obj->mComponents) {
auto it = mResourcesDictionnary.find(c.mObjectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
addObjectToNode(sceneNode, static_cast<Object *>(it->second), c.mTransformation);
}
}
}
void XmlSerializer::ReadObject(XmlNode &node) {
int id = IdNotSet, pid = IdNotSet, pindex = IdNotSet;
bool hasId = getNodeAttribute(node, XmlTag::id, id);
if (!hasId) {
return;
}
bool hasPid = getNodeAttribute(node, XmlTag::pid, pid);
bool hasPindex = getNodeAttribute(node, XmlTag::pindex, pindex);
Object *obj = new Object(id);
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh(currentNode);
mesh->mName.Set(ai_to_string(id));
if (hasPid) {
auto it = mResourcesDictionnary.find(pid);
if (hasPindex && it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
} else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second);
if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0;
}
const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) {
if (name == mMaterials[i]->GetName().C_Str()) {
mesh->mMaterialIndex = static_cast<unsigned int>(i);
}
}
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
mesh->mTextureCoords[0][vertex_idx] =
aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f);
}
} else {
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
if (mesh->mTextureCoords[0][vertex_idx].z < 0) {
// use default
mesh->mTextureCoords[0][vertex_idx] =
aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f);
}
}
}
}else if (it->second->getType() == ResourceType::RT_ColorGroup) {
if (mesh->mColors[0] == nullptr) {
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
ColorGroup *group = static_cast<ColorGroup *>(it->second);
for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) {
mesh->mColors[0][vertex_idx] = group->mColors[pindex];
}
}
}
}
}
obj->mMeshes.push_back(mesh);
obj->mMeshIndex.push_back(mMeshCount);
mMeshCount++;
} else if (currentName == D3MF::XmlTag::components) {
for (XmlNode &currentSubNode : currentNode.children()) {
const std::string subNodeName = currentSubNode.name();
if (subNodeName == D3MF::XmlTag::component) {
int objectId = IdNotSet;
std::string componentTransformStr;
aiMatrix4x4 componentTransform;
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) {
componentTransform = parseTransformMatrix(componentTransformStr);
}
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) {
obj->mComponents.push_back({ objectId, componentTransform });
}
}
}
}
}
mResourcesDictionnary.insert(std::make_pair(id, obj));
}
aiMesh *XmlSerializer::ReadMesh(XmlNode &node) {
if (node.empty()) {
return nullptr;
}
aiMesh *mesh = new aiMesh();
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::vertices) {
ImportVertices(currentNode, mesh);
} else if (currentName == XmlTag::triangles) {
ImportTriangles(currentNode, mesh);
}
}
return mesh;
}
void XmlSerializer::ReadMetadata(XmlNode &node) {
pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name);
const std::string name = attribute.as_string();
const std::string value = node.value();
if (name.empty()) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back(entry);
}
void XmlSerializer::ImportVertices(XmlNode &node, aiMesh *mesh) {
ai_assert(nullptr != mesh);
std::vector<aiVector3D> vertices;
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode));
}
}
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces;
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::triangle) {
int pid = IdNotSet;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
int pindex[3];
aiFace face = ReadTriangle(currentNode, pindex[0], pindex[1], pindex[2]);
if (hasPid && (pindex[0] != IdNotSet || pindex[1] != IdNotSet || pindex[2] != IdNotSet)) {
auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
auto update_material = [&](int idx) {
if (pindex[idx] != IdNotSet) {
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[pindex[idx]];
}
};
update_material(0);
update_material(1);
update_material(2);
} else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
// Load texture coordinates into mesh, when any
Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second); // fix bug
if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0;
}
const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) {
if (name == mMaterials[i]->GetName().C_Str()) {
mesh->mMaterialIndex = static_cast<unsigned int>(i);
}
}
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int vertex_index = 0; vertex_index < mesh->mNumVertices; vertex_index++) {
mesh->mTextureCoords[0][vertex_index].z = IdNotSet;//mark not set
}
}
auto update_texture = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
mesh->mTextureCoords[0][vertex_index] =
aiVector3D(group->mTex2dCoords[pindex[idx]].x, group->mTex2dCoords[pindex[idx]].y, 0.0f);
}
};
update_texture(0);
update_texture(1);
update_texture(2);
} else if (it->second->getType() == ResourceType::RT_ColorGroup) {
// Load vertex color into mesh, when any
ColorGroup *group = static_cast<ColorGroup *>(it->second);
if (mesh->mColors[0] == nullptr) {
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
}
auto update_color = [&](int idx) {
if (pindex[idx] != IdNotSet) {
size_t vertex_index = face.mIndices[idx];
mesh->mColors[0][vertex_index] = group->mColors[pindex[idx]];
}
};
update_color(0);
update_color(1);
update_color(2);
}
}
}
faces.push_back(face);
}
}
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
void XmlSerializer::ReadBaseMaterials(XmlNode &node) {
int id = IdNotSet;
if (getNodeAttribute(node, D3MF::XmlTag::id, id)) {
BaseMaterials *baseMaterials = new BaseMaterials(id);
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::basematerials_base) {
baseMaterials->mMaterialIndex.push_back(static_cast<unsigned int>(mMaterials.size()));
mMaterials.push_back(readMaterialDef(currentNode, id));
}
}
mResourcesDictionnary.insert(std::make_pair(id, baseMaterials));
}
}
void XmlSerializer::ReadEmbeddecTexture(XmlNode &node) {
if (node.empty()) {
return;
}
std::string value;
EmbeddedTexture *tex2D = nullptr;
if (XmlParser::getStdStrAttribute(node, XmlTag::id, value)) {
tex2D = new EmbeddedTexture(atoi(value.c_str()));
}
if (nullptr == tex2D) {
return;
}
if (XmlParser::getStdStrAttribute(node, XmlTag::path, value)) {
tex2D->mPath = value;
}
if (XmlParser::getStdStrAttribute(node, XmlTag::texture_content_type, value)) {
tex2D->mContentType = value;
}
if (XmlParser::getStdStrAttribute(node, XmlTag::texture_tilestyleu, value)) {
tex2D->mTilestyleU = value;
}
if (XmlParser::getStdStrAttribute(node, XmlTag::texture_tilestylev, value)) {
tex2D->mTilestyleV = value;
}
mEmbeddedTextures.emplace_back(tex2D);
StoreEmbeddedTexture(tex2D);
}
void XmlSerializer::StoreEmbeddedTexture(EmbeddedTexture *tex) {
aiMaterial *mat = new aiMaterial;
aiString s;
s.Set(ai_to_string(tex->mId).c_str());
mat->AddProperty(&s, AI_MATKEY_NAME);
const std::string name = "*" + tex->mPath;
s.Set(name);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
aiColor3D col;
mat->AddProperty<aiColor3D>(&col, 1, AI_MATKEY_COLOR_DIFFUSE);
mat->AddProperty<aiColor3D>(&col, 1, AI_MATKEY_COLOR_AMBIENT);
mat->AddProperty<aiColor3D>(&col, 1, AI_MATKEY_COLOR_EMISSIVE);
mat->AddProperty<aiColor3D>(&col, 1, AI_MATKEY_COLOR_SPECULAR);
mMaterials.emplace_back(mat);
}
void XmlSerializer::ReadTextureCoords2D(XmlNode &node, Texture2DGroup *tex2DGroup) {
if (node.empty() || nullptr == tex2DGroup) {
return;
}
int id = IdNotSet;
if (XmlParser::getIntAttribute(node, "texid", id)) {
tex2DGroup->mTexId = id;
}
double value = 0.0;
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
aiVector2D texCoord;
if (currentName == XmlTag::texture_2d_coord) {
XmlParser::getDoubleAttribute(currentNode, XmlTag::texture_cuurd_u, value);
texCoord.x = (ai_real)value;
XmlParser::getDoubleAttribute(currentNode, XmlTag::texture_cuurd_v, value);
texCoord.y = (ai_real)value;
tex2DGroup->mTex2dCoords.push_back(texCoord);
}
}
}
void XmlSerializer::ReadTextureGroup(XmlNode &node) {
if (node.empty()) {
return;
}
int id = IdNotSet;
if (!XmlParser::getIntAttribute(node, XmlTag::id, id)) {
return;
}
Texture2DGroup *group = new Texture2DGroup(id);
ReadTextureCoords2D(node, group);
mResourcesDictionnary.insert(std::make_pair(id, group));
}
aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basematerialsId) {
aiMaterial *material = new aiMaterial();
material->mNumProperties = 0;
std::string name;
bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
std::string stdMaterialName;
const std::string strId(ai_to_string(basematerialsId));
stdMaterialName += "id";
stdMaterialName += strId;
stdMaterialName += "_";
if (hasName) {
stdMaterialName += name;
} else {
stdMaterialName += "basemat_";
stdMaterialName += ai_to_string(mMaterials.size());
}
aiString assimpMaterialName(stdMaterialName);
material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME);
assignDiffuseColor(node, material);
return material;
}
void XmlSerializer::ReadColor(XmlNode &node, ColorGroup *colorGroup) {
if (node.empty() || nullptr == colorGroup) {
return;
}
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::color_item) {
const char *color = currentNode.attribute(XmlTag::color_vaule).as_string();
aiColor4D color_value;
if (parseColor(color, color_value)) {
colorGroup->mColors.push_back(color_value);
}
}
}
}
void XmlSerializer::ReadColorGroup(XmlNode &node) {
if (node.empty()) {
return;
}
int id = IdNotSet;
if (!XmlParser::getIntAttribute(node, XmlTag::id, id)) {
return;
}
ColorGroup *group = new ColorGroup(id);
ReadColor(node, group);
mResourcesDictionnary.insert(std::make_pair(id, group));
}
void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mNumMaterials = static_cast<unsigned int>(mMaterials.size());
if (scene->mNumMaterials == 0) {
return;
}
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
for (size_t i = 0; i < mMaterials.size(); ++i) {
scene->mMaterials[i] = mMaterials[i];
}
}
} // namespace D3MF
} // namespace Assimp

View File

@ -1,99 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#pragma once
#include <assimp/XmlParser.h>
#include <assimp/mesh.h>
#include <vector>
#include <map>
struct aiNode;
struct aiMesh;
struct aiMaterial;
namespace Assimp {
namespace D3MF {
class Resource;
class D3MFOpcPackage;
class Object;
class Texture2DGroup;
class EmbeddedTexture;
class ColorGroup;
class XmlSerializer {
public:
XmlSerializer(XmlParser *xmlParser);
~XmlSerializer();
void ImportXml(aiScene *scene);
private:
void addObjectToNode(aiNode *parent, Object *obj, aiMatrix4x4 nodeTransform);
void ReadObject(XmlNode &node);
aiMesh *ReadMesh(XmlNode &node);
void ReadMetadata(XmlNode &node);
void ImportVertices(XmlNode &node, aiMesh *mesh);
void ImportTriangles(XmlNode &node, aiMesh *mesh);
void ReadBaseMaterials(XmlNode &node);
void ReadEmbeddecTexture(XmlNode &node);
void StoreEmbeddedTexture(EmbeddedTexture *tex);
void ReadTextureCoords2D(XmlNode &node, Texture2DGroup *tex2DGroup);
void ReadTextureGroup(XmlNode &node);
aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId);
void StoreMaterialsInScene(aiScene *scene);
void ReadColorGroup(XmlNode &node);
void ReadColor(XmlNode &node, ColorGroup *colorGroup);
private:
struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::vector<EmbeddedTexture *> mEmbeddedTextures;
std::vector<aiMaterial *> mMaterials;
std::map<unsigned int, Resource *> mResourcesDictionnary;
unsigned int mMeshCount;
XmlParser *mXmlParser;
};
} // namespace D3MF
} // namespace Assimp

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -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>
namespace Assimp { using namespace Assimp;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"AC3D Importer", "AC3D Importer",
"", "",
"", "",
@ -77,8 +77,8 @@ static constexpr aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// skip to the next token // skip to the next token
inline const char *AcSkipToNextToken(const char *buffer, const char *end) { inline const char *AcSkipToNextToken(const char *buffer) {
if (!SkipSpaces(&buffer, end)) { if (!SkipSpaces(&buffer)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
} }
return buffer; return buffer;
@ -86,13 +86,13 @@ inline const char *AcSkipToNextToken(const char *buffer, const char *end) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read a string (may be enclosed in double quotation marks). buffer must point to " // read a string (may be enclosed in double quotation marks). buffer must point to "
inline const char *AcGetString(const char *buffer, const char *end, std::string &out) { inline const char *AcGetString(const char *buffer, std::string &out) {
if (*buffer == '\0') { if (*buffer == '\0') {
throw DeadlyImportError("AC3D: Unexpected EOF in string"); throw DeadlyImportError("AC3D: Unexpected EOF in string");
} }
++buffer; ++buffer;
const char *sz = buffer; const char *sz = buffer;
while ('\"' != *buffer && buffer != end) { while ('\"' != *buffer) {
if (IsLineEnd(*buffer)) { if (IsLineEnd(*buffer)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
out = "ERROR"; out = "ERROR";
@ -112,17 +112,17 @@ inline const char *AcGetString(const char *buffer, const char *end, std::string
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read 1 to n floats prefixed with an optional predefined identifier // read 1 to n floats prefixed with an optional predefined identifier
template <class T> template <class T>
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) { inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
buffer = AcSkipToNextToken(buffer, end); buffer = AcSkipToNextToken(buffer);
if (0 != name_length) { if (0 != name_length) {
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) { if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected."); ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string(name) + " was expected.");
return buffer; return buffer;
} }
buffer += name_length + 1; buffer += name_length + 1;
} }
for (unsigned int _i = 0; _i < num; ++_i) { for (unsigned int _i = 0; _i < num; ++_i) {
buffer = AcSkipToNextToken(buffer, end); buffer = AcSkipToNextToken(buffer);
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]); buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
} }
@ -132,7 +132,7 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
AC3DImporter::AC3DImporter() : AC3DImporter::AC3DImporter() :
mBuffer(), buffer(),
configSplitBFCull(), configSplitBFCull(),
configEvalSubdivision(), configEvalSubdivision(),
mNumMeshes(), mNumMeshes(),
@ -146,13 +146,24 @@ AC3DImporter::AC3DImporter() :
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
AC3DImporter::~AC3DImporter() = default; AC3DImporter::~AC3DImporter() {
// nothing to be done here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
static const uint32_t tokens[] = { AI_MAKE_MAGIC("AC3D") }; std::string extension = GetExtension(pFile);
return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// fixme: are acc and ac3d *really* used? Some sources say they are
if (extension == "ac" || extension == "ac3d" || extension == "acc") {
return true;
}
if (!extension.length() || checkSig) {
uint32_t token = AI_MAKE_MAGIC("AC3D");
return CheckMagicToken(pIOHandler, pFile, &token, 1, 0);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -164,25 +175,25 @@ const aiImporterDesc *AC3DImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a pointer to the next line from the file // Get a pointer to the next line from the file
bool AC3DImporter::GetNextLine() { bool AC3DImporter::GetNextLine() {
SkipLine(&mBuffer.data, mBuffer.end); SkipLine(&buffer);
return SkipSpaces(&mBuffer.data, mBuffer.end); return SkipSpaces(&buffer);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Parse an object section in an AC file // Parse an object section in an AC file
bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) { void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
if (!TokenMatch(mBuffer.data, "OBJECT", 6)) if (!TokenMatch(buffer, "OBJECT", 6))
return false; return;
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
++mNumMeshes; ++mNumMeshes;
objects.emplace_back(); objects.push_back(Object());
Object &obj = objects.back(); Object &obj = objects.back();
aiLight *light = nullptr; aiLight *light = nullptr;
if (!ASSIMP_strincmp(mBuffer.data, "light", 5)) { if (!ASSIMP_strincmp(buffer, "light", 5)) {
// This is a light source. Add it to the list // This is a light source. Add it to the list
mLights->push_back(light = new aiLight()); mLights->push_back(light = new aiLight());
@ -193,71 +204,65 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
// Generate a default name for both the light source and the node // Generate a default name for both the light source and the node
// FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
light->mName.length = ::ai_snprintf(light->mName.data, AI_MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1); light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
obj.name = std::string(light->mName.data); obj.name = std::string(light->mName.data);
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered"); ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
obj.type = Object::Light; obj.type = Object::Light;
} else if (!ASSIMP_strincmp(mBuffer.data, "group", 5)) { } else if (!ASSIMP_strincmp(buffer, "group", 5)) {
obj.type = Object::Group; obj.type = Object::Group;
} else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) { } else if (!ASSIMP_strincmp(buffer, "world", 5)) {
obj.type = Object::World; obj.type = Object::World;
} else } else
obj.type = Object::Poly; obj.type = Object::Poly;
while (GetNextLine()) { while (GetNextLine()) {
if (TokenMatch(mBuffer.data, "kids", 4)) { if (TokenMatch(buffer, "kids", 4)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
unsigned int num = strtoul10(mBuffer.data, &mBuffer.data); unsigned int num = strtoul10(buffer, &buffer);
GetNextLine(); GetNextLine();
if (num) { if (num) {
// load the children of this object recursively // load the children of this object recursively
obj.children.reserve(num); obj.children.reserve(num);
for (unsigned int i = 0; i < num; ++i) { for (unsigned int i = 0; i < num; ++i)
if (!LoadObjectSection(obj.children)) { LoadObjectSection(obj.children);
ASSIMP_LOG_WARN("AC3D: wrong number of kids");
break;
} }
} return;
} } else if (TokenMatch(buffer, "name", 4)) {
return true; SkipSpaces(&buffer);
} else if (TokenMatch(mBuffer.data, "name", 4)) { buffer = AcGetString(buffer, obj.name);
SkipSpaces(&mBuffer.data, mBuffer.data);
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, obj.name);
// If this is a light source, we'll also need to store // If this is a light source, we'll also need to store
// the name of the node in it. // the name of the node in it.
if (light) { if (light) {
light->mName.Set(obj.name); light->mName.Set(obj.name);
} }
} else if (TokenMatch(mBuffer.data, "texture", 7)) { } else if (TokenMatch(buffer, "texture", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
std::string texture; buffer = AcGetString(buffer, obj.texture);
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, texture); } else if (TokenMatch(buffer, "texrep", 6)) {
obj.textures.push_back(texture); SkipSpaces(&buffer);
} else if (TokenMatch(mBuffer.data, "texrep", 6)) { buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texRepeat);
if (!obj.texRepeat.x || !obj.texRepeat.y) if (!obj.texRepeat.x || !obj.texRepeat.y)
obj.texRepeat = aiVector2D(1.f, 1.f); obj.texRepeat = aiVector2D(1.f, 1.f);
} else if (TokenMatch(mBuffer.data, "texoff", 6)) { } else if (TokenMatch(buffer, "texoff", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texOffset); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset);
} else if (TokenMatch(mBuffer.data, "rot", 3)) { } else if (TokenMatch(buffer, "rot", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 9, &obj.rotation); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation);
} else if (TokenMatch(mBuffer.data, "loc", 3)) { } else if (TokenMatch(buffer, "loc", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &obj.translation); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation);
} else if (TokenMatch(mBuffer.data, "subdiv", 6)) { } else if (TokenMatch(buffer, "subdiv", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
obj.subDiv = strtoul10(mBuffer.data, &mBuffer.data); obj.subDiv = strtoul10(buffer, &buffer);
} else if (TokenMatch(mBuffer.data, "crease", 6)) { } else if (TokenMatch(buffer, "crease", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
obj.crease = fast_atof(mBuffer.data); obj.crease = fast_atof(buffer);
} else if (TokenMatch(mBuffer.data, "numvert", 7)) { } else if (TokenMatch(buffer, "numvert", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
unsigned int t = strtoul10(mBuffer.data, &mBuffer.data); unsigned int t = strtoul10(buffer, &buffer);
if (t >= AI_MAX_ALLOC(aiVector3D)) { if (t >= AI_MAX_ALLOC(aiVector3D)) {
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
} }
@ -266,59 +271,59 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
if (!GetNextLine()) { if (!GetNextLine()) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
break; break;
} else if (!IsNumeric(*mBuffer.data)) { } else if (!IsNumeric(*buffer)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet"); ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
--mBuffer.data; // make sure the line is processed a second time --buffer; // make sure the line is processed a second time
break; break;
} }
obj.vertices.emplace_back(); obj.vertices.push_back(aiVector3D());
aiVector3D &v = obj.vertices.back(); aiVector3D &v = obj.vertices.back();
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &v.x); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x);
} }
} else if (TokenMatch(mBuffer.data, "numsurf", 7)) { } else if (TokenMatch(buffer, "numsurf", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
bool Q3DWorkAround = false; bool Q3DWorkAround = false;
const unsigned int t = strtoul10(mBuffer.data, &mBuffer.data); const unsigned int t = strtoul10(buffer, &buffer);
obj.surfaces.reserve(t); obj.surfaces.reserve(t);
for (unsigned int i = 0; i < t; ++i) { for (unsigned int i = 0; i < t; ++i) {
GetNextLine(); GetNextLine();
if (!TokenMatch(mBuffer.data, "SURF", 4)) { if (!TokenMatch(buffer, "SURF", 4)) {
// FIX: this can occur for some files - Quick 3D for // FIX: this can occur for some files - Quick 3D for
// example writes no surf chunks // example writes no surf chunks
if (!Q3DWorkAround) { if (!Q3DWorkAround) {
ASSIMP_LOG_WARN("AC3D: SURF token was expected"); ASSIMP_LOG_WARN("AC3D: SURF token was expected");
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled"); ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
} }
--mBuffer.data; // make sure the line is processed a second time --buffer; // make sure the line is processed a second time
// break; --- see fix notes above // break; --- see fix notes above
Q3DWorkAround = true; Q3DWorkAround = true;
} }
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
obj.surfaces.emplace_back(); obj.surfaces.push_back(Surface());
Surface &surf = obj.surfaces.back(); Surface &surf = obj.surfaces.back();
surf.flags = strtoul_cppstyle(mBuffer.data); surf.flags = strtoul_cppstyle(buffer);
while (true) { while (1) {
if (!GetNextLine()) { if (!GetNextLine()) {
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete"); throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
} }
if (TokenMatch(mBuffer.data, "mat", 3)) { if (TokenMatch(buffer, "mat", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
surf.mat = strtoul10(mBuffer.data); surf.mat = strtoul10(buffer);
} else if (TokenMatch(mBuffer.data, "refs", 4)) { } else if (TokenMatch(buffer, "refs", 4)) {
// --- see fix notes above // --- see fix notes above
if (Q3DWorkAround) { if (Q3DWorkAround) {
if (!surf.entries.empty()) { if (!surf.entries.empty()) {
mBuffer.data -= 6; buffer -= 6;
break; break;
} }
} }
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
const unsigned int m = strtoul10(mBuffer.data); const unsigned int m = strtoul10(buffer);
surf.entries.reserve(m); surf.entries.reserve(m);
obj.numRefs += m; obj.numRefs += m;
@ -328,15 +333,15 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete");
break; break;
} }
surf.entries.emplace_back(); surf.entries.push_back(Surface::SurfaceEntry());
Surface::SurfaceEntry &entry = surf.entries.back(); Surface::SurfaceEntry &entry = surf.entries.back();
entry.first = strtoul10(mBuffer.data, &mBuffer.data); entry.first = strtoul10(buffer, &buffer);
SkipSpaces(&mBuffer.data, mBuffer.end); SkipSpaces(&buffer);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &entry.second); buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
} }
} else { } else {
--mBuffer.data; // make sure the line is processed a second time --buffer; // make sure the line is processed a second time
break; break;
} }
} }
@ -344,7 +349,6 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
} }
} }
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -358,8 +362,8 @@ void AC3DImporter::ConvertMaterial(const Object &object,
s.Set(matSrc.name); s.Set(matSrc.name);
matDest.AddProperty(&s, AI_MATKEY_NAME); matDest.AddProperty(&s, AI_MATKEY_NAME);
} }
if (!object.textures.empty()) { if (object.texture.length()) {
s.Set(object.textures[0]); s.Set(object.texture);
matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
// UV transformation // UV transformation
@ -450,7 +454,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
idx = 0; idx = 0;
} }
if ((*it).entries.empty()) { if ((*it).entries.empty()) {
ASSIMP_LOG_WARN("AC3D: surface has zero vertex references"); ASSIMP_LOG_WARN("AC3D: surface her zero vertex references");
} }
// validate all vertex indices to make sure we won't crash here // validate all vertex indices to make sure we won't crash here
@ -467,32 +471,26 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++node->mNumMeshes; ++node->mNumMeshes;
} }
switch ((*it).GetType()) { switch ((*it).flags & 0xf) {
case Surface::ClosedLine: // closed line // closed line
needMat[idx].first += static_cast<unsigned int>((*it).entries.size()); case 0x1:
needMat[idx].second += static_cast<unsigned int>((*it).entries.size() << 1u); needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
break; break;
// unclosed line // unclosed line
case Surface::OpenLine: case 0x2:
needMat[idx].first += static_cast<unsigned int>((*it).entries.size() - 1); needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += static_cast<unsigned int>(((*it).entries.size() - 1) << 1u); needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
break;
// triangle strip
case Surface::TriangleStrip:
needMat[idx].first += (unsigned int)(*it).entries.size() - 2;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3;
break; break;
// 0 == polygon, else unknown
default: default:
// Coerce unknowns to a polygon and warn if ((*it).flags & 0xf) {
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown: ", (*it).flags); ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(Surface::Mask); (*it).flags &= ~(0xf);
// fallthrough }
// polygon
case Surface::Polygon:
// the number of faces increments by one, the number // the number of faces increments by one, the number
// of vertices by surface.numref. // of vertices by surface.numref.
needMat[idx].first++; needMat[idx].first++;
@ -538,7 +536,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// allocate UV coordinates, but only if the texture name for the // allocate UV coordinates, but only if the texture name for the
// surface is not empty // surface is not empty
aiVector3D *uv = nullptr; aiVector3D *uv = nullptr;
if (!object.textures.empty()) { if (object.texture.length()) {
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2; mesh->mNumUVComponents[0] = 2;
} }
@ -548,8 +546,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
const Surface &src = *it; const Surface &src = *it;
// closed polygon // closed polygon
uint8_t type = (*it).GetType(); unsigned int type = (*it).flags & 0xf;
if (type == Surface::Polygon) { if (!type) {
aiFace &face = *faces++; aiFace &face = *faces++;
face.mNumIndices = (unsigned int)src.entries.size(); face.mNumIndices = (unsigned int)src.entries.size();
if (0 != face.mNumIndices) { if (0 != face.mNumIndices) {
@ -572,62 +570,13 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
} }
} }
} }
} else if (type == Surface::TriangleStrip) {
for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
const Surface::SurfaceEntry &entry1 = src.entries[i];
const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
aiFace &face = *faces++;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = cur++;
face.mIndices[1] = cur++;
face.mIndices[2] = cur++;
if (!(i & 1)) {
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
} else {
*vertices++ = object.vertices[entry2.first] + object.translation;
if (uv) {
uv->x = entry2.second.x;
uv->y = entry2.second.y;
++uv;
}
*vertices++ = object.vertices[entry1.first] + object.translation;
if (uv) {
uv->x = entry1.second.x;
uv->y = entry1.second.y;
++uv;
}
}
if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
throw DeadlyImportError("AC3D: Invalid number of vertices");
}
*vertices++ = object.vertices[entry3.first] + object.translation;
if (uv) {
uv->x = entry3.second.x;
uv->y = entry3.second.y;
++uv;
}
}
} else { } else {
it2 = (*it).entries.begin(); it2 = (*it).entries.begin();
// either a closed or an unclosed line // either a closed or an unclosed line
unsigned int tmp = (unsigned int)(*it).entries.size(); unsigned int tmp = (unsigned int)(*it).entries.size();
if (Surface::OpenLine == type) --tmp; if (0x2 == type) --tmp;
for (unsigned int m = 0; m < tmp; ++m) { for (unsigned int m = 0; m < tmp; ++m) {
aiFace &face = *faces++; aiFace &face = *faces++;
@ -650,7 +599,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
++uv; ++uv;
} }
if (Surface::ClosedLine == type && tmp - 1 == m) { if (0x1 == type && tmp - 1 == m) {
// if this is a closed line repeat its beginning now // if this is a closed line repeat its beginning now
it2 = (*it).entries.begin(); it2 = (*it).entries.begin();
} else } else
@ -676,7 +625,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
if (object.subDiv) { if (object.subDiv) {
if (configEvalSubdivision) { if (configEvalSubdivision) {
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: ", object.name); ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name);
std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr); std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true); div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
@ -684,7 +633,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// previous meshes are deleted vy Subdivide(). // previous meshes are deleted vy Subdivide().
} else { } else {
ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: ", object.name); ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " + object.name);
} }
} }
} }
@ -696,18 +645,18 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// generate a name depending on the type of the node // generate a name depending on the type of the node
switch (object.type) { switch (object.type) {
case Object::Group: case Object::Group:
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACGroup_%i", mGroupsCounter++); node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
break; break;
case Object::Poly: case Object::Poly:
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACPoly_%i", mPolysCounter++); node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
break; break;
case Object::Light: case Object::Light:
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACLight_%i", mLightsCounter++); node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
break; break;
// there shouldn't be more than one world, but we don't care // there shouldn't be more than one world, but we don't care
case Object::World: case Object::World:
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACWorld_%i", mWorldsCounter++); node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
break; break;
} }
} }
@ -747,29 +696,28 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if (file == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AC3D file ", pFile, "."); throw DeadlyImportError("Failed to open AC3D file " + pFile + ".");
} }
// 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
std::vector<char> mBuffer2; std::vector<char> mBuffer2;
TextFileToBuffer(file.get(), mBuffer2); TextFileToBuffer(file.get(), mBuffer2);
mBuffer.data = &mBuffer2[0]; buffer = &mBuffer2[0];
mBuffer.end = &mBuffer2[0] + mBuffer2.size();
mNumMeshes = 0; mNumMeshes = 0;
mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0; mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
if (::strncmp(mBuffer.data, "AC3D", 4)) { if (::strncmp(buffer, "AC3D", 4)) {
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
} }
// print the file format version to the console // print the file format version to the console
unsigned int version = HexDigitToDecimal(mBuffer.data[4]); unsigned int version = HexDigitToDecimal(buffer[4]);
char msg[3]; char msg[3];
ASSIMP_itoa10(msg, 3, version); ASSIMP_itoa10(msg, 3, version);
ASSIMP_LOG_INFO("AC3D file format version: ", msg); ASSIMP_LOG_INFO_F("AC3D file format version: ", msg);
std::vector<Material> materials; std::vector<Material> materials;
materials.reserve(5); materials.reserve(5);
@ -781,36 +729,35 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
mLights = &lights; mLights = &lights;
while (GetNextLine()) { while (GetNextLine()) {
if (TokenMatch(mBuffer.data, "MATERIAL", 8)) { if (TokenMatch(buffer, "MATERIAL", 8)) {
materials.emplace_back(); materials.push_back(Material());
Material &mat = materials.back(); Material &mat = materials.back();
// manually parse the material ... sscanf would use the buldin atof ... // manually parse the material ... sscanf would use the buldin atof ...
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end); buffer = AcSkipToNextToken(buffer);
if ('\"' == *mBuffer.data) { if ('\"' == *buffer) {
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, mat.name); buffer = AcGetString(buffer, mat.name);
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end); buffer = AcSkipToNextToken(buffer);
} }
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "rgb", 3, 3, &mat.rgb); buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "amb", 3, 3, &mat.amb); buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "emis", 4, 3, &mat.emis); buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "spec", 4, 3, &mat.spec); buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "shi", 3, 1, &mat.shin); buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "trans", 5, 1, &mat.trans); buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
} else { }
LoadObjectSection(rootObjects); LoadObjectSection(rootObjects);
} }
}
if (rootObjects.empty() || mNumMeshes == 0u) { if (rootObjects.empty() || !mNumMeshes) {
throw DeadlyImportError("AC3D: No meshes have been loaded"); throw DeadlyImportError("AC3D: No meshes have been loaded");
} }
if (materials.empty()) { if (materials.empty()) {
ASSIMP_LOG_WARN("AC3D: No material has been found"); ASSIMP_LOG_WARN("AC3D: No material has been found");
materials.emplace_back(); materials.push_back(Material());
} }
mNumMeshes += (mNumMeshes >> 2u) + 1; mNumMeshes += (mNumMeshes >> 2u) + 1;
@ -821,7 +768,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
materials.reserve(mNumMeshes); materials.reserve(mNumMeshes);
// generate a dummy root if there are multiple objects on the top layer // generate a dummy root if there are multiple objects on the top layer
Object *root = nullptr; Object *root;
if (1 == rootObjects.size()) if (1 == rootObjects.size())
root = &rootObjects[0]; root = &rootObjects[0];
else { else {
@ -834,7 +781,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
delete root; delete root;
} }
if (::strncmp(pScene->mRootNode->mName.data, "Node", 4) == 0) { if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) {
pScene->mRootNode->mName.Set("<AC3DWorld>"); pScene->mRootNode->mName.Set("<AC3DWorld>");
} }
@ -853,12 +800,10 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
// copy lights // copy lights
pScene->mNumLights = (unsigned int)lights.size(); pScene->mNumLights = (unsigned int)lights.size();
if (!lights.empty()) { if (lights.size()) {
pScene->mLights = new aiLight *[lights.size()]; pScene->mLights = new aiLight *[lights.size()];
::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *)); ::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
} }
} }
} // namespace Assimp
#endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -63,15 +64,12 @@ namespace Assimp {
class AC3DImporter : public BaseImporter { class AC3DImporter : public BaseImporter {
public: public:
AC3DImporter(); AC3DImporter();
~AC3DImporter() override; ~AC3DImporter();
// Represents an AC3D material // Represents an AC3D material
struct Material { struct Material {
Material() : Material() :
rgb(0.6f, 0.6f, 0.6f), rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {}
spec(1.f, 1.f, 1.f),
shin(0.f),
trans(0.f) {}
// base color of the material // base color of the material
aiColor3D rgb; aiColor3D rgb;
@ -98,42 +96,18 @@ public:
// Represents an AC3D surface // Represents an AC3D surface
struct Surface { struct Surface {
Surface() : Surface() :
mat(0), mat(0), flags(0) {}
flags(0) {}
unsigned int mat, flags; unsigned int mat, flags;
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry; typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
std::vector<SurfaceEntry> entries; std::vector<SurfaceEntry> entries;
// Type is low nibble of flags
enum Type : uint8_t {
Polygon = 0x0,
ClosedLine = 0x1,
OpenLine = 0x2,
TriangleStrip = 0x4, // ACC extension (TORCS and Speed Dreams)
Mask = 0xf,
};
inline uint8_t GetType() const { return (flags & Mask); }
}; };
// Represents an AC3D object // Represents an AC3D object
struct Object { struct Object {
Object() : Object() :
type(World), type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {}
name(),
children(),
texRepeat(1.f, 1.f),
texOffset(0.0f, 0.0f),
rotation(),
translation(),
vertices(),
surfaces(),
numRefs(0),
subDiv(0),
crease() {}
// Type description // Type description
enum Type { enum Type {
@ -150,8 +124,7 @@ public:
std::vector<Object> children; std::vector<Object> children;
// texture to be assigned to all surfaces of the object // texture to be assigned to all surfaces of the object
// the .acc format supports up to 4 textures std::string texture;
std::vector<std::string> textures;
// texture repat factors (scaling for all coordinates) // texture repat factors (scaling for all coordinates)
aiVector2D texRepeat, texOffset; aiVector2D texRepeat, texOffset;
@ -185,25 +158,25 @@ public:
* 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;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details */ * See #BaseImporter::GetInfo for the details */
const aiImporterDesc *GetInfo() const override; const aiImporterDesc *GetInfo() const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Imports the given file into the given scene structure. /** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details*/ * See BaseImporter::InternReadFile() for details*/
void InternReadFile(const std::string &pFile, aiScene *pScene, void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler) override; IOSystem *pIOHandler);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ReadFile(). /** Called prior to ReadFile().
* The function is a request to the importer to update its configuration * The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.*/ * basing on the Importer's configuration property list.*/
void SetupProperties(const Importer *pImp) override; void SetupProperties(const Importer *pImp);
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -216,7 +189,7 @@ private:
* load subobjects, the method returns after a 'kids 0' was * load subobjects, the method returns after a 'kids 0' was
* encountered. * encountered.
* @objects List of output objects*/ * @objects List of output objects*/
bool LoadObjectSection(std::vector<Object> &objects); void LoadObjectSection(std::vector<Object> &objects);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Convert all objects into meshes and nodes. /** Convert all objects into meshes and nodes.
@ -242,7 +215,7 @@ private:
private: private:
// points to the next data line // points to the next data line
aiBuffer mBuffer; const char *buffer;
// Configuration option: if enabled, up to two meshes // Configuration option: if enabled, up to two meshes
// are generated per material: those faces who have // are generated per material: those faces who have

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -39,21 +41,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/// \file AMFImporter.cpp
/// \brief AMF-format files importer for Assimp: main algorithm implementation.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
// Header files, Assimp. // Header files, Assimp.
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/StringUtils.h>
// Header files, stdlib. // Header files, stdlib.
#include <memory> #include <memory>
namespace Assimp { namespace Assimp {
static constexpr aiImporterDesc Description = { /// \var aiImporterDesc AMFImporter::Description
/// Conastant which hold importer description
const aiImporterDesc AMFImporter::Description = {
"Additive manufacturing file format(AMF) Importer", "Additive manufacturing file format(AMF) Importer",
"smalcom", "smalcom",
"", "",
@ -73,7 +82,7 @@ void AMFImporter::Clear() {
mTexture_Converted.clear(); mTexture_Converted.clear();
// Delete all elements // Delete all elements
if (!mNodeElement_List.empty()) { if (!mNodeElement_List.empty()) {
for (AMFNodeElementBase *ne : mNodeElement_List) { for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
delete ne; delete ne;
} }
@ -81,14 +90,8 @@ void AMFImporter::Clear() {
} }
} }
AMFImporter::AMFImporter() AI_NO_EXCEPT :
mNodeElement_Cur(nullptr),
mXmlParser(nullptr) {
// empty
}
AMFImporter::~AMFImporter() { AMFImporter::~AMFImporter() {
delete mXmlParser; if (mReader != nullptr) delete mReader;
// Clear() is accounting if data already is deleted. So, just check again if all data is deleted. // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
Clear(); Clear();
} }
@ -97,12 +100,10 @@ AMFImporter::~AMFImporter() {
/************************************************************ Functions: find set ************************************************************/ /************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const { bool AMFImporter::Find_NodeElement(const std::string &pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement **pNodeElement) const {
for (AMFNodeElementBase *ne : mNodeElement_List) { for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
if ((ne->ID == pID) && (ne->Type == pType)) { if ((ne->ID == pID) && (ne->Type == pType)) {
if (pNodeElement != nullptr) { if (pNodeElement != nullptr) *pNodeElement = ne;
*pNodeElement = ne;
}
return true; return true;
} }
@ -111,13 +112,12 @@ bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementB
return false; return false;
} }
bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const { bool AMFImporter::Find_ConvertedNode(const std::string &pID, std::list<aiNode *> &pNodeList, aiNode **pNode) const {
aiString node_name(pID.c_str()); aiString node_name(pID.c_str());
for (aiNode *node : nodeArray) {
for (aiNode *node : pNodeList) {
if (node->mName == node_name) { if (node->mName == node_name) {
if (pNode != nullptr) { if (pNode != nullptr) *pNode = node;
*pNode = node;
}
return true; return true;
} }
@ -129,9 +129,7 @@ bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArra
bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const { bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const {
for (const SPP_Material &mat : mMaterial_Converted) { for (const SPP_Material &mat : mMaterial_Converted) {
if (mat.ID == pID) { if (mat.ID == pID) {
if (pConvertedMaterial != nullptr) { if (pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
*pConvertedMaterial = &mat;
}
return true; return true;
} }
@ -144,42 +142,174 @@ bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Mater
/************************************************************ Functions: throw set ***********************************************************/ /************************************************************ Functions: throw set ***********************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
void AMFImporter::Throw_CloseNotFound(const std::string &nodeName) { void AMFImporter::Throw_CloseNotFound(const std::string &pNode) {
throw DeadlyImportError("Close tag for node <" + nodeName + "> not found. Seems file is corrupt."); throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
} }
void AMFImporter::Throw_IncorrectAttr(const std::string &nodeName, const std::string &attrName) { void AMFImporter::Throw_IncorrectAttr(const std::string &pAttrName) {
throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + attrName + "\"."); throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
} }
void AMFImporter::Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &attrName) { void AMFImporter::Throw_IncorrectAttrValue(const std::string &pAttrName) {
throw DeadlyImportError("Attribute \"" + attrName + "\" in node <" + nodeName + "> has incorrect value."); throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
} }
void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) { void AMFImporter::Throw_MoreThanOnceDefined(const std::string &pNodeType, const std::string &pDescription) {
throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription); throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
} }
void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
throw DeadlyImportError("Not found node with name \"", pID, "\"."); throw DeadlyImportError("Not found node with name \"" + pID + "\".");
} }
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
/************************************************************* Functions: XML set ************************************************************/ /************************************************************* Functions: XML set ************************************************************/
/*********************************************************************************************************************************************/ /*********************************************************************************************************************************************/
void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) { void AMFImporter::XML_CheckNode_MustHaveChildren() {
if (node.children().begin() == node.children().end()) { if (mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children.");
throw DeadlyImportError(std::string("Node <") + node.name() + "> must have children."); }
void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeName) {
static const size_t Uns_Skip_Len = 3;
const char *Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
static bool skipped_before[Uns_Skip_Len] = { false, false, false };
std::string nn(mReader->getNodeName());
bool found = false;
bool close_found = false;
size_t sk_idx;
for (sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) {
if (nn != Uns_Skip[sk_idx]) continue;
found = true;
if (mReader->isEmptyElement()) {
close_found = true;
goto casu_cres;
}
while (mReader->read()) {
if ((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) {
close_found = true;
goto casu_cres;
}
}
} // for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
casu_cres:
if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
if (!close_found) Throw_CloseNotFound(nn);
if (!skipped_before[sk_idx]) {
skipped_before[sk_idx] = true;
ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
} }
} }
bool AMFImporter::XML_SearchNode(const std::string &nodeName) { bool AMFImporter::XML_SearchNode(const std::string &pNodeName) {
return nullptr != mXmlParser->findNode(nodeName); while (mReader->read()) {
if ((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
}
return false;
}
bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) {
std::string val(mReader->getAttributeValue(pAttrIdx));
if ((val == "false") || (val == "0"))
return false;
else if ((val == "true") || (val == "1"))
return true;
else
throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
}
float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) {
std::string val;
float tvalf;
ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) {
return strtoul10(mReader->getAttributeValue(pAttrIdx));
}
float AMFImporter::XML_ReadNode_GetVal_AsFloat() {
std::string val;
float tvalf;
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32() {
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
return strtoul10(mReader->getNodeData());
}
void AMFImporter::XML_ReadNode_GetVal_AsString(std::string &pValue) {
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT)
throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
pValue = mReader->getNodeData();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: parse set ***********************************************************/
/*********************************************************************************************************************************************/
void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement *pNode) {
mNodeElement_Cur->Child.push_back(pNode); // add new element to current element child list.
mNodeElement_Cur = pNode; // switch current element to new one.
}
void AMFImporter::ParseHelper_Node_Exit() {
// check if we can walk up.
if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
}
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
size_t instr_len;
pOutString.clear();
instr_len = strlen(pInStr);
if (!instr_len) return;
pOutString.reserve(instr_len * 3 / 2);
// check and correct floats in format ".x". Must be "x.y".
if (pInStr[0] == '.') pOutString.push_back('0');
pOutString.push_back(pInStr[0]);
for (size_t ci = 1; ci < instr_len; ci++) {
if ((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) {
pOutString.push_back('0');
pOutString.push_back('.');
} else {
pOutString.push_back(pInStr[ci]);
}
}
} }
static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) { static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) {
return (isalnum((unsigned char)pChar) || (pChar == '+') || (pChar == '/')); return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
} }
void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const { void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const {
@ -191,10 +321,7 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
uint8_t arr4[4], arr3[3]; uint8_t arr4[4], arr3[3];
// check input data // check input data
if (pInputBase64.size() % 4) { if (pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
}
// prepare output place // prepare output place
pOutputData.clear(); pOutputData.clear();
pOutputData.reserve(pInputBase64.size() / 4 * 3); pOutputData.reserve(pInputBase64.size() / 4 * 3);
@ -235,34 +362,29 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
} }
void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if (file == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AMF file ", pFile, "."); throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
} }
mXmlParser = new XmlParser(); // generate a XML reader for it
if (!mXmlParser->parse(file.get())) { std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
delete mXmlParser; mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
mXmlParser = nullptr; if (!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
throw DeadlyImportError("Failed to create XML reader for file ", pFile, "."); //
} // start reading
// search for root tag <amf>
// Start reading, search for root tag <amf> if (XML_SearchNode("amf"))
if (!mXmlParser->hasNode("amf")) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
ParseNode_Root(); ParseNode_Root();
} // namespace Assimp else
throw DeadlyImportError("Root node \"amf\" not found.");
void AMFImporter::ParseHelper_Node_Enter(AMFNodeElementBase *node) { delete mReader;
mNodeElement_Cur->Child.push_back(node); // add new element to current element child list. // restore old XMLreader
mNodeElement_Cur = node; mReader = OldReader;
}
void AMFImporter::ParseHelper_Node_Exit() {
if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
} }
// <amf // <amf
@ -273,49 +395,54 @@ void AMFImporter::ParseHelper_Node_Exit() {
// Root XML element. // Root XML element.
// Multi elements - No. // Multi elements - No.
void AMFImporter::ParseNode_Root() { void AMFImporter::ParseNode_Root() {
AMFNodeElementBase *ne = nullptr; std::string unit, version;
XmlNode *root = mXmlParser->findNode("amf"); CAMFImporter_NodeElement *ne(nullptr);
if (nullptr == root) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
XmlNode node = *root;
mUnit = ai_tolower(std::string(node.attribute("unit").as_string()));
mVersion = node.attribute("version").as_string();
// Read attributes for node <amf>. // Read attributes for node <amf>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND_WSKIP;
// Check attributes // Check attributes
if (!mUnit.empty()) { if (!mUnit.empty()) {
if ((mUnit != "inch") && (mUnit != "millimeters") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) { if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit");
Throw_IncorrectAttrValue("unit", mUnit);
}
} }
// create root node element. // create root node element.
ne = new AMFRoot(nullptr); ne = new CAMFImporter_NodeElement_Root(nullptr);
mNodeElement_Cur = ne; // set first "current" element mNodeElement_Cur = ne; // set first "current" element
// and assign attribute's values // and assign attribute's values
((AMFRoot *)ne)->Unit = mUnit; ((CAMFImporter_NodeElement_Root *)ne)->Unit = unit;
((AMFRoot *)ne)->Version = mVersion; ((CAMFImporter_NodeElement_Root *)ne)->Version = version;
// Check for child nodes // Check for child nodes
for (XmlNode &currentNode : node.children() ) { if (!mReader->isEmptyElement()) {
const std::string currentName = currentNode.name(); MACRO_NODECHECK_LOOPBEGIN("amf");
if (currentName == "object") { if (XML_CheckNode_NameEqual("object")) {
ParseNode_Object(currentNode); ParseNode_Object();
} else if (currentName == "material") { continue;
ParseNode_Material(currentNode);
} else if (currentName == "texture") {
ParseNode_Texture(currentNode);
} else if (currentName == "constellation") {
ParseNode_Constellation(currentNode);
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
} }
mNodeElement_Cur = ne; if (XML_CheckNode_NameEqual("material")) {
ParseNode_Material();
continue;
} }
if (XML_CheckNode_NameEqual("texture")) {
ParseNode_Texture();
continue;
}
if (XML_CheckNode_NameEqual("constellation")) {
ParseNode_Constellation();
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("amf");
mNodeElement_Cur = ne; // force restore "current" element mNodeElement_Cur = ne; // force restore "current" element
} // if(!mReader->isEmptyElement())
mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
} }
@ -326,34 +453,40 @@ void AMFImporter::ParseNode_Root() {
// A collection of objects or constellations with specific relative locations. // A collection of objects or constellations with specific relative locations.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Constellation(XmlNode &node) { void AMFImporter::ParseNode_Constellation() {
std::string id; std::string id;
id = node.attribute("id").as_string(); CAMFImporter_NodeElement *ne(nullptr);
// Read attributes for node <constellation>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new grouping object. // create and if needed - define new grouping object.
AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur);
AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience CAMFImporter_NodeElement_Constellation &als = *((CAMFImporter_NodeElement_Constellation *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
if (!id.empty()) als.ID = id;
// Check for child nodes // Check for child nodes
if (!node.empty()) { if (!mReader->isEmptyElement()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { MACRO_NODECHECK_LOOPBEGIN("constellation");
std::string name = currentNode.name(); if (XML_CheckNode_NameEqual("instance")) {
if (name == "instance") { ParseNode_Instance();
ParseNode_Instance(currentNode); continue;
} else if (name == "metadata") {
ParseNode_Metadata(currentNode);
} }
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
} }
MACRO_NODECHECK_LOOPEND("constellation");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} else { } // if(!mReader->isEmptyElement())
mNodeElement_Cur->Child.push_back(ne); else {
} mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -364,43 +497,47 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
// A collection of objects or constellations with specific relative locations. // A collection of objects or constellations with specific relative locations.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Instance(XmlNode &node) { void AMFImporter::ParseNode_Instance() {
AMFNodeElementBase *ne(nullptr); std::string objectid;
CAMFImporter_NodeElement *ne(nullptr);
// Read attributes for node <constellation>. // Read attributes for node <constellation>.
std::string objectid = node.attribute("objectid").as_string(); MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// used object id must be defined, check that. // used object id must be defined, check that.
if (objectid.empty()) { if (objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
}
// create and define new grouping object. // create and define new grouping object.
ne = new AMFInstance(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
AMFInstance &als = *((AMFInstance *)ne);
als.ObjectID = objectid;
if (!node.empty()) { CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience
als.ObjectID = objectid;
// Check for child nodes
if (!mReader->isEmptyElement()) {
bool read_flag[6] = { false, false, false, false, false, false };
als.Delta.Set(0, 0, 0);
als.Rotation.Set(0, 0, 0);
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (auto &currentNode : node.children()) { MACRO_NODECHECK_LOOPBEGIN("instance");
const std::string &currentName = currentNode.name(); MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
if (currentName == "deltax") { MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
XmlParser::getValueAsReal(currentNode, als.Delta.x); MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
} else if (currentName == "deltay") { MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
XmlParser::getValueAsReal(currentNode, als.Delta.y); MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
} else if (currentName == "deltaz") { MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
XmlParser::getValueAsReal(currentNode, als.Delta.z); MACRO_NODECHECK_LOOPEND("instance");
} else if (currentName == "rx") {
XmlParser::getValueAsReal(currentNode, als.Delta.x);
} else if (currentName == "ry") {
XmlParser::getValueAsReal(currentNode, als.Delta.y);
} else if (currentName == "rz") {
XmlParser::getValueAsReal(currentNode, als.Delta.z);
}
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} else { // also convert degrees to radians.
mNodeElement_Cur->Child.push_back(ne); als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
} als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -412,38 +549,51 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
// An object definition. // An object definition.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Object(XmlNode &node) { void AMFImporter::ParseNode_Object() {
AMFNodeElementBase *ne = nullptr; std::string id;
CAMFImporter_NodeElement *ne(nullptr);
// Read attributes for node <object>. // Read attributes for node <object>.
std::string id = node.attribute("id").as_string(); MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create and if needed - define new geometry object. // create and if needed - define new geometry object.
ne = new AMFObject(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur);
AMFObject &als = *((AMFObject *)ne); // alias for convenience CAMFImporter_NodeElement_Object &als = *((CAMFImporter_NodeElement_Object *)ne); // alias for convenience
if (!id.empty()) {
als.ID = id;
}
if (!id.empty()) als.ID = id;
// Check for child nodes // Check for child nodes
if (!node.empty()) { if (!mReader->isEmptyElement()) {
bool col_read = false;
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (auto &currentNode : node.children()) { MACRO_NODECHECK_LOOPBEGIN("object");
const std::string &currentName = currentNode.name(); if (XML_CheckNode_NameEqual("color")) {
if (currentName == "color") { // Check if color already defined for object.
ParseNode_Color(currentNode); if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
} else if (currentName == "mesh") { // read data and set flag about it
ParseNode_Mesh(currentNode); ParseNode_Color();
} else if (currentName == "metadata") { col_read = true;
ParseNode_Metadata(currentNode);
continue;
} }
if (XML_CheckNode_NameEqual("mesh")) {
ParseNode_Mesh();
continue;
} }
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("object");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} else { } // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} } // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -466,23 +616,46 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
// "Revision" - specifies the revision of the entity // "Revision" - specifies the revision of the entity
// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system // "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only) // "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
void AMFImporter::ParseNode_Metadata(XmlNode &node) { void AMFImporter::ParseNode_Metadata() {
AMFNodeElementBase *ne = nullptr; std::string type, value;
CAMFImporter_NodeElement *ne(nullptr);
std::string type = node.attribute("type").as_string(), value;
XmlParser::getValueAsString(node, value);
// read attribute // read attribute
ne = new AMFMetadata(mNodeElement_Cur); MACRO_ATTRREAD_LOOPBEG;
((AMFMetadata *)ne)->Type = type; MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
((AMFMetadata *)ne)->Value = value; MACRO_ATTRREAD_LOOPEND;
// and value of node.
value = mReader->getNodeData();
// Create node element and assign read data.
ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur);
((CAMFImporter_NodeElement_Metadata *)ne)->Type = type;
((CAMFImporter_NodeElement_Metadata *)ne)->Value = value;
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*pCheckSig*/) const { /*********************************************************************************************************************************************/
static const char *tokens[] = { "<amf" }; /******************************************************** Functions: BaseImporter set ********************************************************/
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); /*********************************************************************************************************************************************/
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
const std::string extension = GetExtension(pFile);
if (extension == "amf") {
return true;
}
if (!extension.length() || pCheckSig) {
const char *tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
}
void AMFImporter::GetExtensionList(std::set<std::string> &pExtensionList) {
pExtensionList.insert("amf");
} }
const aiImporterDesc *AMFImporter::GetInfo() const { const aiImporterDesc *AMFImporter::GetInfo() const {

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -52,11 +54,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AMFImporter_Node.hpp" #include "AMFImporter_Node.hpp"
// Header files, Assimp. // Header files, Assimp.
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include "assimp/types.h" #include "assimp/types.h"
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h> #include <assimp/irrXMLWrapper.h>
#include <assimp/importerdesc.h>
#include <assimp/DefaultLogger.hpp>
// Header files, stdlib. // Header files, stdlib.
#include <set> #include <set>
@ -98,41 +100,23 @@ 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 {
using AMFMetaDataArray = std::vector<AMFMetadata *>; private:
using MeshArray = std::vector<aiMesh *>; struct SPP_Material;// forward declaration
using NodeArray = std::vector<aiNode *>;
public:
struct SPP_Material;
/// \struct SPP_Composite
/// 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 {
SPP_Material *Material; ///< Pointer to material - part of composition. SPP_Material* Material;///< Pointer to material - part of composition.
std::string Formula; ///< Formula for calculating ratio of \ref Material. std::string Formula;///< Formula for calculating ratio of \ref Material.
};
/// Data type for post-processing step. More suitable container for texture.
struct SPP_Texture {
std::string ID;
size_t Width, Height, Depth;
bool Tiled;
char FormatHint[9]; // 8 for string + 1 for terminator.
uint8_t *Data;
};
/// Data type for post-processing step. Contain face data.
struct SComplexFace {
aiFace Face; ///< Face vertices.
const AMFColor *Color; ///< Face color. Equal to nullptr if color 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.
}; };
/// \struct SPP_Material
/// Data type for post-processing step. More suitable container for material. /// Data type for post-processing step. More suitable container for material.
struct SPP_Material { struct SPP_Material {
std::string ID; ///< Material ID. std::string ID;///< Material ID.
std::list<AMFMetadata *> Metadata; ///< Metadata of material. std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material.
AMFColor *Color; ///< Color of material. CAMFImporter_NodeElement_Color* Color;///< Color of material.
std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another. std::list<SPP_Composite> Composition;///< List of child materials if current material is composition of few another.
/// Return color calculated for specified coordinate. /// Return color calculated for specified coordinate.
/// \param [in] pX - "x" coordinate. /// \param [in] pX - "x" coordinate.
@ -142,46 +126,68 @@ public:
aiColor4D GetColor(const float pX, const float pY, const float pZ) const; aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
}; };
/// Default constructor. /// Data type for post-processing step. More suitable container for texture.
AMFImporter() AI_NO_EXCEPT; struct SPP_Texture {
std::string ID;
size_t Width, Height, Depth;
bool Tiled;
char FormatHint[9];// 8 for string + 1 for terminator.
uint8_t *Data;
};
/// Default destructor. /// Data type for post-processing step. Contain face data.
~AMFImporter() override; struct SComplexFace {
aiFace Face;///< Face vertices.
const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face.
const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
};
/// 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);
AMFImporter(const AMFImporter &pScene) = delete;
AMFImporter &operator=(const AMFImporter &pScene) = delete;
private:
/// Clear all temporary data. /// Clear all temporary data.
void Clear(); void Clear();
/***********************************************/
/************* Functions: find set *************/
/***********************************************/
/// Find specified node element in node elements list ( \ref mNodeElement_List).
/// \param [in] pID - ID(name) of requested node element.
/// \param [in] pType - type of node element.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node element is found, else - false.
bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const;
/// Find requested aiNode in node list.
/// \param [in] pID - ID(name) of requested node.
/// \param [in] pNodeList - list of nodes where to find the node.
/// \param [out] pNode - pointer to pointer to item found.
/// \return true - if the node is found, else - false.
bool Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const;
/// Find material in list for converted materials. Use at postprocessing step.
/// \param [in] pID - material ID.
/// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material).
/// \return true - if the material is found, else - false.
bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const;
/// Find texture in list of converted textures. Use at postprocessing step,
/// \param [in] pID_R - ID of source "red" texture.
/// \param [in] pID_G - ID of source "green" texture.
/// \param [in] pID_B - ID of source "blue" texture.
/// \param [in] pID_A - ID of source "alpha" texture. Use empty string to find RGB-texture.
/// \param [out] pConvertedTextureIndex - pointer where index in list of found texture will be written. If equivalent to nullptr then nothing will be
/// written.
/// \return true - if the texture is found, else - false.
bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A,
uint32_t* pConvertedTextureIndex = nullptr) const;
/// Get data stored in <vertices> and place it to arrays. /// Get data stored in <vertices> and place it to arrays.
/// \param [in] pNodeElement - reference to node element which kept <object> data. /// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>. /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>.
/// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array /// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array
/// contain nullptr. /// contain nullptr.
void PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray, void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
std::vector<AMFColor *> &pVertexColorArray) const; std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const;
/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
@ -192,24 +198,24 @@ private:
/// \param [in] pID_B - ID of source "blue" texture. /// \param [in] pID_B - ID of source "blue" texture.
/// \param [in] pID_A - ID of source "alpha" texture. /// \param [in] pID_A - ID of source "alpha" texture.
/// \return index of the texture in array of the converted textures. /// \return index of the texture in array of the converted textures.
size_t PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B, const std::string &pID_A); size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A);
/// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc). /// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
/// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after /// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
/// processing. /// processing.
/// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing. /// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated); void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated);
/// Check if child elements of node element is metadata and add it to scene node. /// Check if child elements of node element is metadata and add it to scene node.
/// \param [in] pMetadataList - reference to list with collected metadata. /// \param [in] pMetadataList - reference to list with collected metadata.
/// \param [out] pSceneNode - scene node in which metadata will be added. /// \param [out] pSceneNode - scene node in which metadata will be added.
void Postprocess_AddMetadata(const AMFMetaDataArray &pMetadataList, aiNode &pSceneNode) const; void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const;
/// To create aiMesh and aiNode for it from <object>. /// To create aiMesh and aiNode for it from <object>.
/// \param [in] pNodeElement - reference to node element which kept <object> data. /// \param [in] pNodeElement - reference to node element which kept <object> data.
/// \param [out] meshList - reference to a list with all aiMesh of the scene. /// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - pointer to place where new aiNode will be created. /// \param [out] pSceneNode - pointer to place where new aiNode will be created.
void Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode); void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode);
/// Create mesh for every <volume> in <mesh>. /// Create mesh for every <volume> in <mesh>.
/// \param [in] pNodeElement - reference to node element which kept <mesh> data. /// \param [in] pNodeElement - reference to node element which kept <mesh> data.
@ -220,89 +226,207 @@ private:
/// \param [in] pMaterialList - reference to a list with defined materials. /// \param [in] pMaterialList - reference to a list with defined materials.
/// \param [out] pMeshList - reference to a list with all aiMesh of the scene. /// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
/// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's. /// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
void Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray, void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor, const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor,
MeshArray &pMeshList, aiNode &pSceneNode); std::list<aiMesh*>& pMeshList, aiNode& pSceneNode);
/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material. /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material. /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
void Postprocess_BuildMaterial(const AMFMaterial &pMaterial); void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial);
/// Create and add to aiNode's list new part of scene graph defined by <constellation>. /// Create and add to aiNode's list new part of scene graph defined by <constellation>.
/// \param [in] pConstellation - reference to <constellation> node. /// \param [in] pConstellation - reference to <constellation> node.
/// \param [out] nodeArray - reference to aiNode's list. /// \param [out] pNodeList - reference to aiNode's list.
void Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const; void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const;
/// Build Assimp scene graph in aiScene from collected data. /// Build Assimp scene graph in aiScene from collected data.
/// \param [out] pScene - pointer to aiScene where tree will be built. /// \param [out] pScene - pointer to aiScene where tree will be built.
void Postprocess_BuildScene(aiScene *pScene); void Postprocess_BuildScene(aiScene* pScene);
/// Call that function when close tag of node not found and exception must be raised.
/// E.g.:
/// <amf>
/// <object>
/// </amf> <!--- object not closed --->
/// \throw DeadlyImportError.
/// \param [in] pNode - node name in which exception happened.
void Throw_CloseNotFound(const std::string& pNode);
/// Call that function when attribute name is incorrect and exception must be raised.
/// \param [in] pAttrName - attribute name.
/// \throw DeadlyImportError.
void Throw_IncorrectAttr(const std::string& pAttrName);
/// Call that function when attribute value is incorrect and exception must be raised.
/// \param [in] pAttrName - attribute name.
/// \throw DeadlyImportError.
void Throw_IncorrectAttrValue(const std::string& pAttrName);
/// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised.
/// E.g.:
/// <object>
/// <color>... <!--- color defined --->
/// <color>... <!--- color defined again --->
/// </object>
/// \throw DeadlyImportError.
/// \param [in] pNodeType - type of node which defined one more time.
/// \param [in] pDescription - message about error. E.g. what the node defined while exception raised.
void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription);
/// Call that function when referenced element ID are not found in graph and exception must be raised.
/// \param [in] pID - ID of of element which not found.
/// \throw DeadlyImportError.
void Throw_ID_NotFound(const std::string& pID) const;
/// Check if current node have children: <node>...</node>. If not then exception will throwed.
void XML_CheckNode_MustHaveChildren();
/// Check if current node name is equal to pNodeName.
/// \param [in] pNodeName - name for checking.
/// return true if current node name is equal to pNodeName, else - false.
bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
/// \param [in] pParentNodeName - parent node name. Used for reporting.
void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName);
/// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end.
/// \param [in] pNodeName - requested node name.
/// return true - if node is found, else - false.
bool XML_SearchNode(const std::string& pNodeName);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx);
/// Read node value.
/// \return read data.
float XML_ReadNode_GetVal_AsFloat();
/// Read node value.
/// \return read data.
uint32_t XML_ReadNode_GetVal_AsU32();
/// Read node value.
/// \return read data.
void XML_ReadNode_GetVal_AsString(std::string& pValue);
/// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called.
/// \param [in] pNode - new current node.
void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode);
/// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin.
void ParseHelper_Node_Exit();
/// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it
/// must be converted to right form - "0.xxx".
/// \param [in] pInStr - pointer to input string which can contain incorrect form of values.
/// \param [out[ pOutString - output string with right form of values.
void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString);
/// Decode Base64-encoded data. /// Decode Base64-encoded data.
/// \param [in] pInputBase64 - reference to input Base64-encoded string. /// \param [in] pInputBase64 - reference to input Base64-encoded string.
/// \param [out] pOutputData - reference to output array for decoded data. /// \param [out] pOutputData - reference to output array for decoded data.
void ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const; void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const;
/// Parse <AMF> node of the file. /// Parse <AMF> node of the file.
void ParseNode_Root(); void ParseNode_Root();
/// Parse <constellation> node of the file. /// Parse <constellation> node of the file.
void ParseNode_Constellation(XmlNode &node); void ParseNode_Constellation();
/// Parse <instance> node of the file. /// Parse <instance> node of the file.
void ParseNode_Instance(XmlNode &node); void ParseNode_Instance();
/// Parse <material> node of the file. /// Parse <material> node of the file.
void ParseNode_Material(XmlNode &node); void ParseNode_Material();
/// Parse <metadata> node. /// Parse <metadata> node.
void ParseNode_Metadata(XmlNode &node); void ParseNode_Metadata();
/// Parse <object> node of the file. /// Parse <object> node of the file.
void ParseNode_Object(XmlNode &node); void ParseNode_Object();
/// Parse <texture> node of the file. /// Parse <texture> node of the file.
void ParseNode_Texture(XmlNode &node); void ParseNode_Texture();
/// Parse <coordinates> node of the file. /// Parse <coordinates> node of the file.
void ParseNode_Coordinates(XmlNode &node); void ParseNode_Coordinates();
/// Parse <edge> node of the file. /// Parse <edge> node of the file.
void ParseNode_Edge(XmlNode &node); void ParseNode_Edge();
/// Parse <mesh> node of the file. /// Parse <mesh> node of the file.
void ParseNode_Mesh(XmlNode &node); void ParseNode_Mesh();
/// Parse <triangle> node of the file. /// Parse <triangle> node of the file.
void ParseNode_Triangle(XmlNode &node); void ParseNode_Triangle();
/// Parse <vertex> node of the file. /// Parse <vertex> node of the file.
void ParseNode_Vertex(XmlNode &node); void ParseNode_Vertex();
/// Parse <vertices> node of the file. /// Parse <vertices> node of the file.
void ParseNode_Vertices(XmlNode &node); void ParseNode_Vertices();
/// Parse <volume> node of the file. /// Parse <volume> node of the file.
void ParseNode_Volume(XmlNode &node); void ParseNode_Volume();
/// Parse <color> node of the file. /// Parse <color> node of the file.
void ParseNode_Color(XmlNode &node); void ParseNode_Color();
/// Parse <texmap> of <map> node of the file. /// Parse <texmap> of <map> node of the file.
/// \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(const bool pUseOldName = false);
public:
/// Default constructor.
AMFImporter() AI_NO_EXCEPT
: mNodeElement_Cur(nullptr)
, mReader(nullptr) {
// empty
}
/// Default destructor.
~AMFImporter();
/// 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);
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const;
void GetExtensionList(std::set<std::string>& pExtensionList);
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
const aiImporterDesc* GetInfo ()const;
AMFImporter(const AMFImporter& pScene) = delete;
AMFImporter& operator=(const AMFImporter& pScene) = delete;
private: private:
AMFNodeElementBase *mNodeElement_Cur; ///< Current element. static const aiImporterDesc Description;
std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph.
XmlParser *mXmlParser; CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
std::string mUnit; std::string mUnit;
std::string mVersion; std::list<SPP_Material> mMaterial_Converted;///< List of converted materials for postprocessing step.
std::list<SPP_Material> mMaterial_Converted; ///< List of converted materials for postprocessing step. std::list<SPP_Texture> mTexture_Converted;///< List of converted textures for postprocessing step.
std::list<SPP_Texture> mTexture_Converted; ///< List of converted textures for postprocessing step.
}; };
} // namespace Assimp }// namespace Assimp
#endif // INCLUDED_AI_AMF_IMPORTER_H #endif // INCLUDED_AI_AMF_IMPORTER_H

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -39,50 +41,58 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/// \file AMFImporter_Geometry.cpp
/// \brief Parsing data from geometry nodes.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
#include <assimp/ParsingUtils.h> #include "AMFImporter_Macro.hpp"
namespace Assimp { namespace Assimp
{
// <mesh> // <mesh>
// </mesh> // </mesh>
// A 3D mesh hull. // A 3D mesh hull.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <object>. // Parent element - <object>.
void AMFImporter::ParseNode_Mesh(XmlNode &node) { void AMFImporter::ParseNode_Mesh()
AMFNodeElementBase *ne = nullptr; {
CAMFImporter_NodeElement* ne;
// Check for child nodes
if (0 != ASSIMP_stricmp(node.name(), "mesh")) {
return;
}
// create new mesh object. // create new mesh object.
ne = new AMFMesh(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Mesh(mNodeElement_Cur);
bool found_verts = false, found_volumes = false; // Check for child nodes
if (!node.empty()) { if(!mReader->isEmptyElement())
{
bool vert_read = false;
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
pugi::xml_node vertNode = node.child("vertices"); MACRO_NODECHECK_LOOPBEGIN("mesh");
if (!vertNode.empty()) { if(XML_CheckNode_NameEqual("vertices"))
ParseNode_Vertices(vertNode); {
found_verts = true; // Check if data already defined.
if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
// read data and set flag about it
ParseNode_Vertices();
vert_read = true;
continue;
} }
pugi::xml_node volumeNode = node.child("volume"); if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; }
if (!volumeNode.empty()) { MACRO_NODECHECK_LOOPEND("mesh");
ParseNode_Volume(volumeNode);
found_volumes = true;
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} }// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
if (!found_verts && !found_volumes) { mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
mNodeElement_Cur->Child.push_back(ne);
} // if(!mReader->isEmptyElement()) else
// and to node element list because its a new object in graph.
mNodeElement_List.push_back(ne);
} }
// <vertices> // <vertices>
@ -90,25 +100,27 @@ void AMFImporter::ParseNode_Mesh(XmlNode &node) {
// The list of vertices to be used in defining triangles. // The list of vertices to be used in defining triangles.
// Multi elements - No. // Multi elements - No.
// Parent element - <mesh>. // Parent element - <mesh>.
void AMFImporter::ParseNode_Vertices(XmlNode &node) { void AMFImporter::ParseNode_Vertices()
AMFNodeElementBase *ne = nullptr; {
CAMFImporter_NodeElement* ne;
// create new mesh object. // create new mesh object.
ne = new AMFVertices(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Vertices(mNodeElement_Cur);
// Check for child nodes // Check for child nodes
if (node.empty()) { if(!mReader->isEmptyElement())
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element {
return;
}
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (XmlNode &currentNode : node.children()) { MACRO_NODECHECK_LOOPBEGIN("vertices");
const std::string &currentName = currentNode.name(); if(XML_CheckNode_NameEqual("vertex")) { ParseNode_Vertex(); continue; }
if (currentName == "vertex") { MACRO_NODECHECK_LOOPEND("vertices");
ParseNode_Vertex(currentNode);
}
}
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. }// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
} }
// <vertex> // <vertex>
@ -116,35 +128,52 @@ void AMFImporter::ParseNode_Vertices(XmlNode &node) {
// A vertex to be referenced in triangles. // A vertex to be referenced in triangles.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <vertices>. // Parent element - <vertices>.
void AMFImporter::ParseNode_Vertex(XmlNode &node) { void AMFImporter::ParseNode_Vertex()
AMFNodeElementBase *ne = nullptr; {
CAMFImporter_NodeElement* ne;
// create new mesh object. // create new mesh object.
ne = new AMFVertex(mNodeElement_Cur); ne = new CAMFImporter_NodeElement_Vertex(mNodeElement_Cur);
// Check for child nodes // Check for child nodes
pugi::xml_node colorNode = node.child("color"); if(!mReader->isEmptyElement())
{
bool col_read = false; bool col_read = false;
bool coord_read = false; bool coord_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
if (!colorNode.empty()) { MACRO_NODECHECK_LOOPBEGIN("vertex");
ParseNode_Color(colorNode); if(XML_CheckNode_NameEqual("color"))
{
// Check if data already defined.
if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
continue;
} }
pugi::xml_node coordNode = node.child("coordinates");
if (!coordNode.empty()) { if(XML_CheckNode_NameEqual("coordinates"))
ParseNode_Coordinates(coordNode); {
// Check if data already defined.
if(coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Coordinates();
coord_read = true; coord_read = true;
continue;
} }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("vertex");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} }// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
if (!coord_read && !col_read) { mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
// <coordinates> // <coordinates>
@ -157,76 +186,94 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) {
// <x>, <y>, <z> // <x>, <y>, <z>
// Multi elements - No. // Multi elements - No.
// X, Y, or Z coordinate, respectively, of a vertex position in space. // X, Y, or Z coordinate, respectively, of a vertex position in space.
void AMFImporter::ParseNode_Coordinates(XmlNode &node) { void AMFImporter::ParseNode_Coordinates()
AMFNodeElementBase *ne = nullptr; {
if (!node.empty()) { CAMFImporter_NodeElement* ne;
ne = new AMFCoordinates(mNodeElement_Cur);
ParseHelper_Node_Enter(ne);
for (XmlNode &currentNode : node.children()) {
// create new color object. // create new color object.
AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience ne = new CAMFImporter_NodeElement_Coordinates(mNodeElement_Cur);
const std::string &currentName = ai_tolower(currentNode.name());
if (currentName == "x") { CAMFImporter_NodeElement_Coordinates& als = *((CAMFImporter_NodeElement_Coordinates*)ne);// alias for convenience
XmlParser::getValueAsReal(currentNode, als.Coordinate.x);
} else if (currentName == "y") { // Check for child nodes
XmlParser::getValueAsReal(currentNode, als.Coordinate.y); if(!mReader->isEmptyElement())
} else if (currentName == "z") { {
XmlParser::getValueAsReal(currentNode, als.Coordinate.z); bool read_flag[3] = { false, false, false };
}
} ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("coordinates");
MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x);
MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y);
MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z);
MACRO_NODECHECK_LOOPEND("coordinates");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
// check that all components was defined
if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined.");
} else { }// if(!mReader->isEmptyElement())
mNodeElement_Cur->Child.push_back(new AMFCoordinates(mNodeElement_Cur)); else
} {
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
} }
// <volume // <volume
// materialid="" - Which material to use. // materialid="" - Which material to use.
// type="" - What this volume describes can be "region" or "support". If none specified, "object" is assumed. If support, then the geometric // type="" - What this volume describes can be “region” or “support”. If none specified, “object” is assumed. If support, then the geometric
// requirements 1-8 listed in section 5 do not need to be maintained. // requirements 1-8 listed in section 5 do not need to be maintained.
// > // >
// </volume> // </volume>
// Defines a volume from the established vertex list. // Defines a volume from the established vertex list.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <mesh>. // Parent element - <mesh>.
void AMFImporter::ParseNode_Volume(XmlNode &node) { void AMFImporter::ParseNode_Volume()
std::string materialid; {
std::string type; std::string materialid;
AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur); std::string type;
CAMFImporter_NodeElement* ne;
// Read attributes for node <color>. // Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create new object.
ne = new CAMFImporter_NodeElement_Volume(mNodeElement_Cur);
// and assign read data // and assign read data
((CAMFImporter_NodeElement_Volume*)ne)->MaterialID = materialid;
((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string(); ((CAMFImporter_NodeElement_Volume*)ne)->Type = type;
((AMFVolume *)ne)->Type = type;
// Check for child nodes // Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false; bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (auto &currentNode : node.children()) { MACRO_NODECHECK_LOOPBEGIN("volume");
const std::string currentName = currentNode.name(); if(XML_CheckNode_NameEqual("color"))
if (currentName == "color") { {
if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <volume>."); // Check if data already defined.
ParseNode_Color(currentNode); if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <volume>.");
// read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
} else if (currentName == "triangle") {
ParseNode_Triangle(currentNode); continue;
} else if (currentName == "metadata") {
ParseNode_Metadata(currentNode);
} else if (currentName == "volume") {
ParseNode_Metadata(currentNode);
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} }
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. if(XML_CheckNode_NameEqual("triangle")) { ParseNode_Triangle(); continue; }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("volume");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
} }
// <triangle> // <triangle>
@ -239,46 +286,72 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
// <v1>, <v2>, <v3> // <v1>, <v2>, <v3>
// Multi elements - No. // Multi elements - No.
// Index of the desired vertices in a triangle or edge. // Index of the desired vertices in a triangle or edge.
void AMFImporter::ParseNode_Triangle(XmlNode &node) { void AMFImporter::ParseNode_Triangle()
AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur); {
CAMFImporter_NodeElement* ne;
// create new triangle object. // create new color object.
ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience CAMFImporter_NodeElement_Triangle& als = *((CAMFImporter_NodeElement_Triangle*)ne);// alias for convenience
// Check for child nodes
if(!mReader->isEmptyElement())
{
bool col_read = false, tex_read = false;
bool read_flag[3] = { false, false, false };
bool col_read = false;
if (!node.empty()) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
std::string v; MACRO_NODECHECK_LOOPBEGIN("triangle");
for (auto &currentNode : node.children()) { if(XML_CheckNode_NameEqual("color"))
const std::string currentName = currentNode.name(); {
if (currentName == "color") { // Check if data already defined.
if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <triangle>."); if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <triangle>.");
ParseNode_Color(currentNode); // read data and set flag about it
ParseNode_Color();
col_read = true; col_read = true;
} else if (currentName == "texmap") {
ParseNode_TexMap(currentNode); continue;
} else if (currentName == "map") {
ParseNode_TexMap(currentNode, true);
} else if (currentName == "v1") {
XmlParser::getValueAsString(currentNode, v);
als.V[0] = std::atoi(v.c_str());
} else if (currentName == "v2") {
XmlParser::getValueAsString(currentNode, v);
als.V[1] = std::atoi(v.c_str());
} else if (currentName == "v3") {
XmlParser::getValueAsString(currentNode, v);
als.V[2] = std::atoi(v.c_str());
}
}
ParseHelper_Node_Exit();
} else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} }
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. if(XML_CheckNode_NameEqual("texmap"))// new name of node: "texmap".
{
// Check if data already defined.
if(tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for <triangle>.");
// read data and set flag about it
ParseNode_TexMap();
tex_read = true;
continue;
}
else if(XML_CheckNode_NameEqual("map"))// old name of node: "map".
{
// Check if data already defined.
if(tex_read) Throw_MoreThanOnceDefined("map", "Only one texture coordinate can be defined for <triangle>.");
// read data and set flag about it
ParseNode_TexMap(true);
tex_read = true;
continue;
}
MACRO_NODECHECK_READCOMP_U32("v1", read_flag[0], als.V[0]);
MACRO_NODECHECK_READCOMP_U32("v2", read_flag[1], als.V[1]);
MACRO_NODECHECK_READCOMP_U32("v3", read_flag[2], als.V[2]);
MACRO_NODECHECK_LOOPEND("triangle");
ParseHelper_Node_Exit();
// check that all components was defined
if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined.");
}// if(!mReader->isEmptyElement())
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}// if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
} }
} // namespace Assimp }// namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER #endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -0,0 +1,166 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/// \file AMFImporter_Macro.hpp
/// \brief Useful macrodefines.
/// \date 2016
/// \author smal.root@gmail.com
#pragma once
#ifndef AMFIMPORTER_MACRO_HPP_INCLUDED
#define AMFIMPORTER_MACRO_HPP_INCLUDED
/// \def MACRO_ATTRREAD_LOOPBEG
/// Begin of loop that read attributes values.
#define MACRO_ATTRREAD_LOOPBEG \
for(int idx = 0, idx_end = mReader->getAttributeCount(); idx < idx_end; idx++) \
{ \
std::string an(mReader->getAttributeName(idx));
/// \def MACRO_ATTRREAD_LOOPEND
/// End of loop that read attributes values.
#define MACRO_ATTRREAD_LOOPEND \
Throw_IncorrectAttr(an); \
}
/// \def MACRO_ATTRREAD_LOOPEND_WSKIP
/// End of loop that read attributes values. Difference from \ref MACRO_ATTRREAD_LOOPEND in that: current macro skip unknown attributes, but
/// \ref MACRO_ATTRREAD_LOOPEND throw an exception.
#define MACRO_ATTRREAD_LOOPEND_WSKIP \
continue; \
}
/// \def MACRO_ATTRREAD_CHECK_REF
/// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
/// "continue" will called.
/// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name.
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
#define MACRO_ATTRREAD_CHECK_REF(pAttrName, pVarName, pFunction) \
if(an == pAttrName) \
{ \
pFunction(idx, pVarName); \
continue; \
}
/// \def MACRO_ATTRREAD_CHECK_RET
/// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
/// If result was read then "continue" will called.
/// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name.
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
#define MACRO_ATTRREAD_CHECK_RET(pAttrName, pVarName, pFunction) \
if(an == pAttrName) \
{ \
pVarName = pFunction(idx); \
continue; \
}
/// \def MACRO_NODECHECK_LOOPBEGIN(pNodeName)
/// Begin of loop of parsing child nodes. Do not add ';' at end.
/// \param [in] pNodeName - current node name.
#define MACRO_NODECHECK_LOOPBEGIN(pNodeName) \
do { \
bool close_found = false; \
\
while(mReader->read()) \
{ \
if(mReader->getNodeType() == irr::io::EXN_ELEMENT) \
{
/// \def MACRO_NODECHECK_LOOPEND(pNodeName)
/// End of loop of parsing child nodes.
/// \param [in] pNodeName - current node name.
#define MACRO_NODECHECK_LOOPEND(pNodeName) \
XML_CheckNode_SkipUnsupported(pNodeName); \
}/* if(mReader->getNodeType() == irr::io::EXN_ELEMENT) */ \
else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) \
{ \
if(XML_CheckNode_NameEqual(pNodeName)) \
{ \
close_found = true; \
\
break; \
} \
}/* else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) */ \
}/* while(mReader->read()) */ \
\
if(!close_found) Throw_CloseNotFound(pNodeName); \
\
} while(false)
/// \def MACRO_NODECHECK_READCOMP_F
/// Check current node name and if it equal to requested then read value. Result write to output variable of type "float".
/// If result was read then "continue" will called. Also check if node data already read then raise exception.
/// \param [in] pNodeName - node name.
/// \param [in, out] pReadFlag - read flag.
/// \param [out] pVarName - output variable name.
#define MACRO_NODECHECK_READCOMP_F(pNodeName, pReadFlag, pVarName) \
if(XML_CheckNode_NameEqual(pNodeName)) \
{ \
/* Check if field already read before. */ \
if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \
/* Read color component and assign it to object. */ \
pVarName = XML_ReadNode_GetVal_AsFloat(); \
pReadFlag = true; \
continue; \
}
/// \def MACRO_NODECHECK_READCOMP_U32
/// Check current node name and if it equal to requested then read value. Result write to output variable of type "uint32_t".
/// If result was read then "continue" will called. Also check if node data already read then raise exception.
/// \param [in] pNodeName - node name.
/// \param [in, out] pReadFlag - read flag.
/// \param [out] pVarName - output variable name.
#define MACRO_NODECHECK_READCOMP_U32(pNodeName, pReadFlag, pVarName) \
if(XML_CheckNode_NameEqual(pNodeName)) \
{ \
/* Check if field already read before. */ \
if(pReadFlag) Throw_MoreThanOnceDefined(pNodeName, "Only one component can be defined."); \
/* Read color component and assign it to object. */ \
pVarName = XML_ReadNode_GetVal_AsU32(); \
pReadFlag = true; \
continue; \
}
#endif // AMFIMPORTER_MACRO_HPP_INCLUDED

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -47,8 +49,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
#include "AMFImporter_Macro.hpp"
namespace Assimp { namespace Assimp
{
// <color // <color
// profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>. // profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>.
@ -64,46 +68,51 @@ namespace Assimp {
// Multi elements - No. // Multi elements - No.
// Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The // Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
// values can be specified as constants, or as a formula depending on the coordinates. // values can be specified as constants, or as a formula depending on the coordinates.
void AMFImporter::ParseNode_Color(XmlNode &node) { void AMFImporter::ParseNode_Color() {
if (node.empty()) { std::string profile;
return; CAMFImporter_NodeElement* ne;
}
// Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("profile", profile, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
const std::string &profile = node.attribute("profile").as_string();
bool read_flag[4] = { false, false, false, false };
AMFNodeElementBase *ne = new AMFColor(mNodeElement_Cur);
AMFColor &als = *((AMFColor *)ne); // alias for convenience
ParseHelper_Node_Enter(ne);
for (pugi::xml_node &child : node.children()) {
// create new color object. // create new color object.
als.Profile = profile; ne = new CAMFImporter_NodeElement_Color(mNodeElement_Cur);
const std::string &name = child.name(); CAMFImporter_NodeElement_Color& als = *((CAMFImporter_NodeElement_Color*)ne);// alias for convenience
if ( name == "r") {
read_flag[0] = true; als.Profile = profile;
XmlParser::getValueAsFloat(child, als.Color.r); // Check for child nodes
} else if (name == "g") { if(!mReader->isEmptyElement())
read_flag[1] = true; {
XmlParser::getValueAsFloat(child, als.Color.g); bool read_flag[4] = { false, false, false, false };
} else if (name == "b") {
read_flag[2] = true; ParseHelper_Node_Enter(ne);
XmlParser::getValueAsFloat(child, als.Color.b); MACRO_NODECHECK_LOOPBEGIN("color");
} else if (name == "a") { MACRO_NODECHECK_READCOMP_F("r", read_flag[0], als.Color.r);
read_flag[3] = true; MACRO_NODECHECK_READCOMP_F("g", read_flag[1], als.Color.g);
XmlParser::getValueAsFloat(child, als.Color.a); MACRO_NODECHECK_READCOMP_F("b", read_flag[2], als.Color.b);
} MACRO_NODECHECK_READCOMP_F("a", read_flag[3], als.Color.a);
// check if <a> is absent. Then manually add "a == 1". MACRO_NODECHECK_LOOPEND("color");
if (!read_flag[3]) {
als.Color.a = 1;
}
}
als.Composed = false;
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
// check that all components was defined // check that all components was defined
if (!(read_flag[0] && read_flag[1] && read_flag[2])) { if (!(read_flag[0] && read_flag[1] && read_flag[2])) {
throw DeadlyImportError("Not all color components are defined."); throw DeadlyImportError("Not all color components are defined.");
} }
// check if <a> is absent. Then manually add "a == 1".
if (!read_flag[3]) {
als.Color.a = 1;
}
}
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
}
als.Composed = false;
mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
} }
// <material // <material
@ -113,25 +122,45 @@ void AMFImporter::ParseNode_Color(XmlNode &node) {
// An available material. // An available material.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Material(XmlNode &node) { void AMFImporter::ParseNode_Material() {
// create new object and assign read data std::string id;
std::string id = node.attribute("id").as_string(); CAMFImporter_NodeElement* ne;
AMFNodeElementBase *ne = new AMFMaterial(mNodeElement_Cur);
((AMFMaterial*)ne)->ID = id; // Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create new object.
ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur);
// and assign read data
((CAMFImporter_NodeElement_Material*)ne)->ID = id;
// Check for child nodes // Check for child nodes
if (!node.empty()) { if(!mReader->isEmptyElement())
{
bool col_read = false;
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for (pugi::xml_node &child : node.children()) { MACRO_NODECHECK_LOOPBEGIN("material");
const std::string name = child.name(); if(XML_CheckNode_NameEqual("color"))
if (name == "color") { {
ParseNode_Color(child); // Check if data already defined.
} else if (name == "metadata") { if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <material>.");
ParseNode_Metadata(child); // read data and set flag about it
} ParseNode_Color();
col_read = true;
continue;
} }
if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
MACRO_NODECHECK_LOOPEND("material");
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} else { }
else
{
mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
} }
@ -154,39 +183,51 @@ void AMFImporter::ParseNode_Material(XmlNode &node) {
// then layer by layer. // then layer by layer.
// Multi elements - Yes. // Multi elements - Yes.
// Parent element - <amf>. // Parent element - <amf>.
void AMFImporter::ParseNode_Texture(XmlNode &node) { void AMFImporter::ParseNode_Texture()
const std::string id = node.attribute("id").as_string(); {
const uint32_t width = node.attribute("width").as_uint(); std::string id;
const uint32_t height = node.attribute("height").as_uint(); uint32_t width = 0;
uint32_t depth = node.attribute("depth").as_uint(); uint32_t height = 0;
const std::string type = node.attribute("type").as_string(); uint32_t depth = 1;
bool tiled = node.attribute("tiled").as_bool(); std::string type;
bool tiled = false;
std::string enc64_data;
if (node.empty()) { // Read attributes for node <color>.
return; MACRO_ATTRREAD_LOOPBEG;
} MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("width", width, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("depth", depth, XML_ReadNode_GetAttrVal_AsU32);
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("tiled", tiled, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// create new texture object. // create new texture object.
AMFNodeElementBase *ne = new AMFTexture(mNodeElement_Cur); CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur);
AMFTexture& als = *((AMFTexture*)ne);// alias for convenience CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience
std::string enc64_data;
XmlParser::getValueAsString(node, enc64_data);
// Check for child nodes // Check for child nodes
if (!mReader->isEmptyElement()) {
XML_ReadNode_GetVal_AsString(enc64_data);
}
// check that all components was defined // check that all components was defined
if (id.empty()) { if (id.empty()) {
throw DeadlyImportError("ID for texture must be defined."); throw DeadlyImportError("ID for texture must be defined.");
} }
if (width < 1) { if (width < 1) {
throw DeadlyImportError("Invalid width for texture."); Throw_IncorrectAttrValue("width");
} }
if (height < 1) { if (height < 1) {
throw DeadlyImportError("Invalid height for texture."); Throw_IncorrectAttrValue("height");
}
if (depth < 1) {
Throw_IncorrectAttrValue("depth");
} }
if (type != "grayscale") { if (type != "grayscale") {
throw DeadlyImportError("Invalid type for texture."); Throw_IncorrectAttrValue("type");
} }
if (enc64_data.empty()) { if (enc64_data.empty()) {
throw DeadlyImportError("Texture data not defined."); throw DeadlyImportError("Texture data not defined.");
@ -198,9 +239,7 @@ void AMFImporter::ParseNode_Texture(XmlNode &node) {
als.Depth = depth; als.Depth = depth;
als.Tiled = tiled; als.Tiled = tiled;
ParseHelper_Decode_Base64(enc64_data, als.Data); ParseHelper_Decode_Base64(enc64_data, als.Data);
if (depth == 0) {
depth = (uint32_t)(als.Data.size() / (width * height));
}
// check data size // check data size
if ((width * height * depth) != als.Data.size()) { if ((width * height * depth) != als.Data.size()) {
throw DeadlyImportError("Texture has incorrect data size."); throw DeadlyImportError("Texture has incorrect data size.");
@ -224,93 +263,57 @@ void AMFImporter::ParseNode_Texture(XmlNode &node) {
// <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>. // <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
// Multi elements - No. // Multi elements - No.
// Texture coordinates for every vertex of triangle. // Texture coordinates for every vertex of triangle.
void AMFImporter::ParseNode_TexMap(XmlNode &node, const bool pUseOldName) { void AMFImporter::ParseNode_TexMap(const bool pUseOldName) {
// Read attributes for node <color>.
AMFNodeElementBase *ne = new AMFTexMap(mNodeElement_Cur);
AMFTexMap &als = *((AMFTexMap *)ne); //
std::string rtexid, gtexid, btexid, atexid; std::string rtexid, gtexid, btexid, atexid;
if (!node.empty()) {
for (pugi::xml_attribute &attr : node.attributes()) {
const std::string &currentAttr = attr.name();
if (currentAttr == "rtexid") {
rtexid = attr.as_string();
} else if (currentAttr == "gtexid") {
gtexid = attr.as_string();
} else if (currentAttr == "btexid") {
btexid = attr.as_string();
} else if (currentAttr == "atexid") {
atexid = attr.as_string();
}
}
}
// create new texture coordinates object, alias for convenience // Read attributes for node <color>.
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("rtexid", rtexid, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("gtexid", gtexid, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("btexid", btexid, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("atexid", atexid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// create new texture coordinates object.
CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience
// check data // check data
if (rtexid.empty() && gtexid.empty() && btexid.empty()) { if(rtexid.empty() && gtexid.empty() && btexid.empty()) throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
}
// Check for children nodes // Check for children nodes
if (node.children().begin() == node.children().end()) { XML_CheckNode_MustHaveChildren();
throw DeadlyImportError("Invalid children definition.");
}
// read children nodes // read children nodes
bool read_flag[6] = { false, false, false, false, false, false }; bool read_flag[6] = { false, false, false, false, false, false };
if (!pUseOldName) {
ParseHelper_Node_Enter(ne); ParseHelper_Node_Enter(ne);
for ( XmlNode &currentNode : node.children()) { if(!pUseOldName)
const std::string &name = currentNode.name(); {
if (name == "utex1") { MACRO_NODECHECK_LOOPBEGIN("texmap");
read_flag[0] = true; MACRO_NODECHECK_READCOMP_F("utex1", read_flag[0], als.TextureCoordinate[0].x);
XmlParser::getValueAsReal(node, als.TextureCoordinate[0].x); MACRO_NODECHECK_READCOMP_F("utex2", read_flag[1], als.TextureCoordinate[1].x);
} else if (name == "utex2") { MACRO_NODECHECK_READCOMP_F("utex3", read_flag[2], als.TextureCoordinate[2].x);
read_flag[1] = true; MACRO_NODECHECK_READCOMP_F("vtex1", read_flag[3], als.TextureCoordinate[0].y);
XmlParser::getValueAsReal(node, als.TextureCoordinate[1].x); MACRO_NODECHECK_READCOMP_F("vtex2", read_flag[4], als.TextureCoordinate[1].y);
} else if (name == "utex3") { MACRO_NODECHECK_READCOMP_F("vtex3", read_flag[5], als.TextureCoordinate[2].y);
read_flag[2] = true; MACRO_NODECHECK_LOOPEND("texmap");
XmlParser::getValueAsReal(node, als.TextureCoordinate[2].x);
} else if (name == "vtex1") {
read_flag[3] = true;
XmlParser::getValueAsReal(node, als.TextureCoordinate[0].y);
} else if (name == "vtex2") {
read_flag[4] = true;
XmlParser::getValueAsReal(node, als.TextureCoordinate[1].y);
} else if (name == "vtex3") {
read_flag[5] = true;
XmlParser::getValueAsReal(node, als.TextureCoordinate[2].y);
}
} }
else
{
MACRO_NODECHECK_LOOPBEGIN("map");
MACRO_NODECHECK_READCOMP_F("u1", read_flag[0], als.TextureCoordinate[0].x);
MACRO_NODECHECK_READCOMP_F("u2", read_flag[1], als.TextureCoordinate[1].x);
MACRO_NODECHECK_READCOMP_F("u3", read_flag[2], als.TextureCoordinate[2].x);
MACRO_NODECHECK_READCOMP_F("v1", read_flag[3], als.TextureCoordinate[0].y);
MACRO_NODECHECK_READCOMP_F("v2", read_flag[4], als.TextureCoordinate[1].y);
MACRO_NODECHECK_READCOMP_F("v3", read_flag[5], als.TextureCoordinate[2].y);
MACRO_NODECHECK_LOOPEND("map");
}// if(!pUseOldName) else
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
} else {
for (pugi::xml_attribute &attr : node.attributes()) {
const std::string name = attr.name();
if (name == "u") {
read_flag[0] = true;
als.TextureCoordinate[0].x = attr.as_float();
} else if (name == "u2") {
read_flag[1] = true;
als.TextureCoordinate[1].x = attr.as_float();
} else if (name == "u3") {
read_flag[2] = true;
als.TextureCoordinate[2].x = attr.as_float();
} else if (name == "v1") {
read_flag[3] = true;
als.TextureCoordinate[0].y = attr.as_float();
} else if (name == "v2") {
read_flag[4] = true;
als.TextureCoordinate[1].y = attr.as_float();
} else if (name == "v3") {
read_flag[5] = true;
als.TextureCoordinate[0].y = attr.as_float();
}
}
}
// check that all components was defined // check that all components was defined
if (!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) { if(!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5]))
throw DeadlyImportError("Not all texture coordinates are defined."); throw DeadlyImportError("Not all texture coordinates are defined.");
}
// copy attributes data // copy attributes data
als.TextureID_R = rtexid; als.TextureID_R = rtexid;
@ -318,7 +321,7 @@ void AMFImporter::ParseNode_TexMap(XmlNode &node, const bool pUseOldName) {
als.TextureID_B = btexid; als.TextureID_B = btexid;
als.TextureID_A = atexid; als.TextureID_A = atexid;
mNodeElement_List.push_back(ne); mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
} }
}// namespace Assimp }// namespace Assimp

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -48,21 +50,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H #ifndef INCLUDED_AI_AMF_IMPORTER_NODE_H
#define INCLUDED_AI_AMF_IMPORTER_NODE_H #define INCLUDED_AI_AMF_IMPORTER_NODE_H
// Header files, Assimp. // Header files, stdlib.
#include <assimp/scene.h>
#include <assimp/types.h>
#include <list> #include <list>
#include <string> #include <string>
#include <vector> #include <vector>
// Header files, Assimp.
#include "assimp/types.h"
#include "assimp/scene.h"
/// \class CAMFImporter_NodeElement
/// Base class for elements of nodes. /// Base class for elements of nodes.
class AMFNodeElementBase { class CAMFImporter_NodeElement {
public: public:
/// Define what data type contain node element. /// Define what data type contain node element.
enum EType { enum EType {
ENET_Color, ///< Color element: <color>. ENET_Color, ///< Color element: <color>.
ENET_Constellation, ///< Grouping element: <constellation>. ENET_Constellation,///< Grouping element: <constellation>.
ENET_Coordinates, ///< Coordinates element: <coordinates>. ENET_Coordinates, ///< Coordinates element: <coordinates>.
ENET_Edge, ///< Edge element: <edge>. ENET_Edge, ///< Edge element: <edge>.
ENET_Instance, ///< Grouping element: <constellation>. ENET_Instance, ///< Grouping element: <constellation>.
@ -81,43 +85,51 @@ public:
ENET_Invalid ///< Element has invalid type and possible contain invalid data. ENET_Invalid ///< Element has invalid type and possible contain invalid data.
}; };
const EType Type; ///< Type of element. const EType Type;///< Type of element.
std::string ID; ///< ID of element. std::string ID;///< ID of element.
AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root. CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root.
std::list<AMFNodeElementBase *> Child; ///< Child elements. std::list<CAMFImporter_NodeElement*> Child;///< Child elements.
public: /// Destructor, virtual.. public: /// Destructor, virtual..
virtual ~AMFNodeElementBase() = default; virtual ~CAMFImporter_NodeElement() {
// empty
}
/// Disabled copy constructor and co. /// Disabled copy constructor and co.
AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete; CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete;
AMFNodeElementBase(AMFNodeElementBase &&) = delete; CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete;
AMFNodeElementBase &operator=(const AMFNodeElementBase &pNodeElement) = delete; CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete;
AMFNodeElementBase() = delete; CAMFImporter_NodeElement() = delete;
protected: protected:
/// In constructor inheritor must set element type. /// In constructor inheritor must set element type.
/// \param [in] pType - element type. /// \param [in] pType - element type.
/// \param [in] pParent - parent element. /// \param [in] pParent - parent element.
AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) : CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent)
Type(pType), Parent(pParent) { : Type(pType)
, ID()
, Parent(pParent)
, Child() {
// empty // empty
} }
}; // class IAMFImporter_NodeElement };// class IAMFImporter_NodeElement
/// \struct CAMFImporter_NodeElement_Constellation
/// A collection of objects or constellations with specific relative locations. /// A collection of objects or constellations with specific relative locations.
struct AMFConstellation : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFConstellation(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Constellation, pParent) {} : CAMFImporter_NodeElement(ENET_Constellation, pParent)
{}
}; // struct CAMFImporter_NodeElement_Constellation };// struct CAMFImporter_NodeElement_Constellation
/// \struct CAMFImporter_NodeElement_Instance
/// Part of constellation. /// Part of constellation.
struct AMFInstance : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
std::string ObjectID; ///< ID of object for instantiation. std::string ObjectID;///< ID of object for instantiation.
/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to /// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
/// create an instance of the object in the current constellation. /// create an instance of the object in the current constellation.
aiVector3D Delta; aiVector3D Delta;
@ -128,36 +140,42 @@ struct AMFInstance : public AMFNodeElementBase {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFInstance(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Instance, pParent) {} : CAMFImporter_NodeElement(ENET_Instance, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Metadata
/// Structure that define metadata node. /// Structure that define metadata node.
struct AMFMetadata : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement {
std::string Type; ///< Type of "Value". std::string Type;///< Type of "Value".
std::string Value; ///< Value. std::string Value;///< Value.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFMetadata(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Metadata, pParent) {} : CAMFImporter_NodeElement(ENET_Metadata, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Root
/// Structure that define root node. /// Structure that define root node.
struct AMFRoot : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement {
std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron". std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
std::string Version; ///< Version of format. std::string Version;///< Version of format.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFRoot(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Root, pParent) {} : CAMFImporter_NodeElement(ENET_Root, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Color
/// Structure that define object node. /// Structure that define object node.
struct AMFColor : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement {
bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA. std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA.
aiColor4D Color; ///< Constant color. aiColor4D Color; ///< Constant color.
@ -165,122 +183,156 @@ struct AMFColor : public AMFNodeElementBase {
/// @brief Constructor. /// @brief Constructor.
/// @param [in] pParent - pointer to parent node. /// @param [in] pParent - pointer to parent node.
AMFColor(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color() { : CAMFImporter_NodeElement(ENET_Color, pParent)
, Composed( false )
, Color()
, Profile() {
// empty // empty
} }
}; };
/// \struct CAMFImporter_NodeElement_Material
/// Structure that define material node. /// Structure that define material node.
struct AMFMaterial : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFMaterial(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Material, pParent) {} : CAMFImporter_NodeElement(ENET_Material, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Object
/// Structure that define object node. /// Structure that define object node.
struct AMFObject : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFObject(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Object, pParent) {} : CAMFImporter_NodeElement(ENET_Object, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Mesh /// \struct CAMFImporter_NodeElement_Mesh
/// Structure that define mesh node. /// Structure that define mesh node.
struct AMFMesh : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFMesh(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Mesh, pParent) {} : CAMFImporter_NodeElement(ENET_Mesh, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Vertex
/// Structure that define vertex node. /// Structure that define vertex node.
struct AMFVertex : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFVertex(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Vertex, pParent) {} : CAMFImporter_NodeElement(ENET_Vertex, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Edge
/// Structure that define edge node. /// Structure that define edge node.
struct AMFEdge : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFEdge(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Edge, pParent) {} : CAMFImporter_NodeElement(ENET_Edge, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Vertices
/// Structure that define vertices node. /// Structure that define vertices node.
struct AMFVertices : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement {
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFVertices(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Vertices, pParent) {} : CAMFImporter_NodeElement(ENET_Vertices, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Volume
/// Structure that define volume node. /// Structure that define volume node.
struct AMFVolume : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement {
std::string MaterialID; ///< Which material to use. std::string MaterialID;///< Which material to use.
std::string Type; ///< What this volume describes can be "region" or "support". If none specified, "object" is assumed. std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFVolume(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Volume, pParent) {} : CAMFImporter_NodeElement(ENET_Volume, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_Coordinates
/// Structure that define coordinates node. /// Structure that define coordinates node.
struct AMFCoordinates : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement
aiVector3D Coordinate; ///< Coordinate. {
aiVector3D Coordinate;///< Coordinate.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFCoordinates(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Coordinates, pParent) {} : CAMFImporter_NodeElement(ENET_Coordinates, pParent)
{}
}; };
/// \struct CAMFImporter_NodeElement_TexMap
/// Structure that define texture coordinates node. /// Structure that define texture coordinates node.
struct AMFTexMap : public AMFNodeElementBase { struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement {
aiVector3D TextureCoordinate[3]; ///< Texture coordinates. aiVector3D TextureCoordinate[3];///< Texture coordinates.
std::string TextureID_R; ///< Texture ID for red color component. std::string TextureID_R;///< Texture ID for red color component.
std::string TextureID_G; ///< Texture ID for green color component. std::string TextureID_G;///< Texture ID for green color component.
std::string TextureID_B; ///< Texture ID for blue color component. std::string TextureID_B;///< Texture ID for blue color component.
std::string TextureID_A; ///< Texture ID for alpha color component. std::string TextureID_A;///< Texture ID for alpha color component.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFTexMap(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{} { : CAMFImporter_NodeElement(ENET_TexMap, pParent)
, TextureCoordinate{}
, TextureID_R()
, TextureID_G()
, TextureID_B()
, TextureID_A() {
// empty // empty
} }
}; };
/// \struct CAMFImporter_NodeElement_Triangle
/// Structure that define triangle node. /// Structure that define triangle node.
struct AMFTriangle : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement {
size_t V[3]; ///< Triangle vertices. size_t V[3];///< Triangle vertices.
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFTriangle(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Triangle, pParent) { : CAMFImporter_NodeElement(ENET_Triangle, pParent) {
// empty // empty
} }
}; };
/// Structure that define texture node. /// Structure that define texture node.
struct AMFTexture : public AMFNodeElementBase { struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement {
size_t Width, Height, Depth; ///< Size of the texture. size_t Width, Height, Depth;///< Size of the texture.
std::vector<uint8_t> Data; ///< Data of the texture. std::vector<uint8_t> Data;///< Data of the texture.
bool Tiled; bool Tiled;
/// Constructor. /// Constructor.
/// \param [in] pParent - pointer to parent node. /// \param [in] pParent - pointer to parent node.
AMFTexture(AMFNodeElementBase *pParent) : CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent)
AMFNodeElementBase(ENET_Texture, pParent), Width(0), Height(0), Depth(0), Data(), Tiled(false) { : CAMFImporter_NodeElement(ENET_Texture, pParent)
, Width( 0 )
, Height( 0 )
, Depth( 0 )
, Data()
, Tiled( false ){
// empty // empty
} }
}; };

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -48,10 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AMFImporter.hpp" #include "AMFImporter.hpp"
// Header files, Assimp.
#include <assimp/SceneCombiner.h> #include <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h> #include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
// Header files, stdlib.
#include <iterator> #include <iterator>
namespace Assimp { namespace Assimp {
@ -62,13 +66,11 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
// Check if stored data are supported. // Check if stored data are supported.
if (!Composition.empty()) { if (!Composition.empty()) {
throw DeadlyImportError("IME. GetColor for composition"); throw DeadlyImportError("IME. GetColor for composition");
} } else if (Color->Composed) {
if (Color->Composed) {
throw DeadlyImportError("IME. GetColor, composed color"); throw DeadlyImportError("IME. GetColor, composed color");
} } else {
tcol = Color->Color; tcol = Color->Color;
}
// Check if default color must be used // Check if default color must be used
if ((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) { if ((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) {
@ -81,61 +83,61 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
return tcol; return tcol;
} }
void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &nodeElement, std::vector<aiVector3D> &vertexCoordinateArray, void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
std::vector<AMFColor *> &pVertexColorArray) const { std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray) const {
AMFVertices *vn = nullptr; CAMFImporter_NodeElement_Vertices *vn = nullptr;
size_t col_idx; size_t col_idx;
// All data stored in "vertices", search for it. // All data stored in "vertices", search for it.
for (AMFNodeElementBase *ne_child : nodeElement.Child) { for (CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
if (ne_child->Type == AMFNodeElementBase::ENET_Vertices) { if (ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices *)ne_child;
vn = (AMFVertices*)ne_child;
}
} }
// If "vertices" not found then no work for us. // If "vertices" not found then no work for us.
if (vn == nullptr) { if (vn == nullptr) return;
return;
}
// all coordinates stored as child and we need to reserve space for future push_back's. pVertexCoordinateArray.reserve(vn->Child.size()); // all coordinates stored as child and we need to reserve space for future push_back's.
vertexCoordinateArray.reserve(vn->Child.size()); pVertexColorArray.resize(vn->Child.size()); // colors count equal vertices count.
// colors count equal vertices count.
pVertexColorArray.resize(vn->Child.size());
col_idx = 0; col_idx = 0;
// Inside vertices collect all data and place to arrays // Inside vertices collect all data and place to arrays
for (AMFNodeElementBase *vn_child : vn->Child) { for (CAMFImporter_NodeElement *vn_child : vn->Child) {
// vertices, colors // vertices, colors
if (vn_child->Type == AMFNodeElementBase::ENET_Vertex) { if (vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) {
// by default clear color for current vertex // by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr; pVertexColorArray[col_idx] = nullptr;
for (AMFNodeElementBase *vtx : vn_child->Child) { for (CAMFImporter_NodeElement *vtx : vn_child->Child) {
if (vtx->Type == AMFNodeElementBase::ENET_Coordinates) { if (vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates) {
vertexCoordinateArray.push_back(((AMFCoordinates *)vtx)->Coordinate); pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates *)vtx)->Coordinate);
continue; continue;
} }
if (vtx->Type == AMFNodeElementBase::ENET_Color) { if (vtx->Type == CAMFImporter_NodeElement::ENET_Color) {
pVertexColorArray[col_idx] = (AMFColor *)vtx; pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color *)vtx;
continue; continue;
} }
} } // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
++col_idx; col_idx++;
} } // if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
} } // for(CAMFImporter_NodeElement* vn_child: vn->Child)
} }
size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) { size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B,
if (r.empty() && g.empty() && b.empty() && a.empty()) { const std::string &pID_A) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined."); size_t TextureConverted_Index;
} std::string TextureConverted_ID;
std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a; // check input data
size_t TextureConverted_Index = 0; if (pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty())
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
// Create ID
TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A;
// Check if texture specified by set of IDs is converted already.
TextureConverted_Index = 0;
for (const SPP_Texture &tex_convd : mTexture_Converted) { for (const SPP_Texture &tex_convd : mTexture_Converted) {
if (tex_convd.ID == TextureConverted_ID) { if (tex_convd.ID == TextureConverted_ID) {
return TextureConverted_Index; return TextureConverted_Index;
@ -144,60 +146,52 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
} }
} }
//
// Converted texture not found, create it. // Converted texture not found, create it.
AMFTexture *src_texture[4] { //
nullptr CAMFImporter_NodeElement_Texture *src_texture[4]{ nullptr };
}; std::vector<CAMFImporter_NodeElement_Texture *> src_texture_4check;
std::vector<AMFTexture *> src_texture_4check;
SPP_Texture converted_texture; SPP_Texture converted_texture;
{ // find all specified source textures { // find all specified source textures
AMFNodeElementBase *t_tex = nullptr; CAMFImporter_NodeElement *t_tex;
// R // R
if (!r.empty()) { if (!pID_R.empty()) {
if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) { if (!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
Throw_ID_NotFound(r);
}
src_texture[0] = (AMFTexture *)t_tex; src_texture[0] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex); src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else { } else {
src_texture[0] = nullptr; src_texture[0] = nullptr;
} }
// G // G
if (!g.empty()) { if (!pID_G.empty()) {
if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) { if (!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
Throw_ID_NotFound(g);
}
src_texture[1] = (AMFTexture *)t_tex; src_texture[1] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex); src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else { } else {
src_texture[1] = nullptr; src_texture[1] = nullptr;
} }
// B // B
if (!b.empty()) { if (!pID_B.empty()) {
if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) { if (!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
Throw_ID_NotFound(b);
}
src_texture[2] = (AMFTexture *)t_tex; src_texture[2] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex); src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else { } else {
src_texture[2] = nullptr; src_texture[2] = nullptr;
} }
// A // A
if (!a.empty()) { if (!pID_A.empty()) {
if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) { if (!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
Throw_ID_NotFound(a);
}
src_texture[3] = (AMFTexture *)t_tex; src_texture[3] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex); src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else { } else {
src_texture[3] = nullptr; src_texture[3] = nullptr;
} }
@ -219,38 +213,38 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
converted_texture.Depth = src_texture_4check[0]->Depth; converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too. // if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false; converted_texture.Tiled = false;
for (uint8_t i = 0; i < src_texture_4check.size(); ++i) { for (uint8_t i = 0; i < src_texture_4check.size(); i++)
converted_texture.Tiled |= src_texture_4check[i]->Tiled; converted_texture.Tiled |= src_texture_4check[i]->Tiled;
}
// Create format hint. // Create format hint.
constexpr char templateColor[] = "rgba0000"; strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
memcpy(converted_texture.FormatHint, templateColor, 8); if (!pID_R.empty()) converted_texture.FormatHint[4] = '8';
if (!r.empty()) converted_texture.FormatHint[4] = '8'; if (!pID_G.empty()) converted_texture.FormatHint[5] = '8';
if (!g.empty()) converted_texture.FormatHint[5] = '8'; if (!pID_B.empty()) converted_texture.FormatHint[6] = '8';
if (!b.empty()) converted_texture.FormatHint[6] = '8'; if (!pID_A.empty()) converted_texture.FormatHint[7] = '8';
if (!a.empty()) converted_texture.FormatHint[7] = '8';
//
// Сopy data of textures. // Сopy data of textures.
//
size_t tex_size = 0; size_t tex_size = 0;
size_t step = 0; size_t step = 0;
size_t off_g = 0; size_t off_g = 0;
size_t off_b = 0; size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied. // Calculate size of the target array and rule how data will be copied.
if (!r.empty() && nullptr != src_texture[0]) { if (!pID_R.empty() && nullptr != src_texture[0]) {
tex_size += src_texture[0]->Data.size(); tex_size += src_texture[0]->Data.size();
step++, off_g++, off_b++; step++, off_g++, off_b++;
} }
if (!g.empty() && nullptr != src_texture[1]) { if (!pID_G.empty() && nullptr != src_texture[1]) {
tex_size += src_texture[1]->Data.size(); tex_size += src_texture[1]->Data.size();
step++, off_b++; step++, off_b++;
} }
if (!b.empty() && nullptr != src_texture[2]) { if (!pID_B.empty() && nullptr != src_texture[2]) {
tex_size += src_texture[2]->Data.size(); tex_size += src_texture[2]->Data.size();
step++; step++;
} }
if (!a.empty() && nullptr != src_texture[3]) { if (!pID_A.empty() && nullptr != src_texture[3]) {
tex_size += src_texture[3]->Data.size(); tex_size += src_texture[3]->Data.size();
step++; step++;
} }
@ -261,17 +255,17 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void { auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
if (!pID.empty()) { if (!pID.empty()) {
for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) { for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
AMFTexture *tex = src_texture[pSrcTexNum]; CAMFImporter_NodeElement_Texture *tex = src_texture[pSrcTexNum];
ai_assert(tex); ai_assert(tex);
converted_texture.Data[idx_target] = tex->Data.at(idx_src); converted_texture.Data[idx_target] = tex->Data.at(idx_src);
} }
} }
}; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(r, 0, step, 0); CopyTextureData(pID_R, 0, step, 0);
CopyTextureData(g, off_g, step, 1); CopyTextureData(pID_G, off_g, step, 1);
CopyTextureData(b, off_b, step, 2); CopyTextureData(pID_B, off_b, step, 2);
CopyTextureData(a, step - 1, step, 3); CopyTextureData(pID_A, step - 1, step, 3);
// Store new converted texture ID // Store new converted texture ID
converted_texture.ID = TextureConverted_ID; converted_texture.ID = TextureConverted_ID;
@ -282,7 +276,7 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
} }
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) { void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) {
auto texmap_is_equal = [](const AMFTexMap *pTexMap1, const AMFTexMap *pTexMap2) -> bool { auto texmap_is_equal = [](const CAMFImporter_NodeElement_TexMap *pTexMap1, const CAMFImporter_NodeElement_TexMap *pTexMap2) -> bool {
if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true; if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
if (pTexMap1 == nullptr) return false; if (pTexMap1 == nullptr) return false;
if (pTexMap2 == nullptr) return false; if (pTexMap2 == nullptr) return false;
@ -319,80 +313,73 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
} while (!pInputList.empty()); } while (!pInputList.empty());
} }
void AMFImporter::Postprocess_AddMetadata(const AMFMetaDataArray &metadataList, aiNode &sceneNode) const { void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata *> &metadataList, aiNode &sceneNode) const {
if (metadataList.empty()) { if (!metadataList.empty()) {
return; if (sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
}
if (sceneNode.mMetaData != nullptr) {
throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
}
// copy collected metadata to output node. // copy collected metadata to output node.
sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size())); sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size()));
size_t meta_idx(0); size_t meta_idx(0);
for (const AMFMetadata *metadata : metadataList) { for (const CAMFImporter_NodeElement_Metadata &metadata : metadataList) {
sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata->Type, aiString(metadata->Value)); sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
} }
} // if(!metadataList.empty())
} }
void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode) { void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object &pNodeElement, std::list<aiMesh *> &pMeshList, aiNode **pSceneNode) {
AMFColor *object_color = nullptr; CAMFImporter_NodeElement_Color *object_color = nullptr;
// create new aiNode and set name as <object> has. // create new aiNode and set name as <object> has.
*pSceneNode = new aiNode; *pSceneNode = new aiNode;
(*pSceneNode)->mName = pNodeElement.ID; (*pSceneNode)->mName = pNodeElement.ID;
// read mesh and color // read mesh and color
for (const AMFNodeElementBase *ne_child : pNodeElement.Child) { for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
std::vector<aiVector3D> vertex_arr; std::vector<aiVector3D> vertex_arr;
std::vector<AMFColor *> color_arr; std::vector<CAMFImporter_NodeElement_Color *> color_arr;
// color for object // color for object
if (ne_child->Type == AMFNodeElementBase::ENET_Color) { if (ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color *)ne_child;
object_color = (AMFColor *) ne_child;
}
if (ne_child->Type == AMFNodeElementBase::ENET_Mesh) { if (ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) {
// Create arrays from children of mesh: vertices. // Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((AMFMesh *)ne_child), vertex_arr, color_arr); PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh // Use this arrays as a source when creating every aiMesh
Postprocess_BuildMeshSet(*((AMFMesh *)ne_child), vertex_arr, color_arr, object_color, meshList, **pSceneNode); Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
} }
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement) } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
} }
void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray, void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor, MeshArray &pMeshList, aiNode &pSceneNode) { const std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray,
const CAMFImporter_NodeElement_Color *pObjectColor, std::list<aiMesh *> &pMeshList, aiNode &pSceneNode) {
std::list<unsigned int> mesh_idx; std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it. // all data stored in "volume", search for it.
for (const AMFNodeElementBase *ne_child : pNodeElement.Child) { for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
const AMFColor *ne_volume_color = nullptr; const CAMFImporter_NodeElement_Color *ne_volume_color = nullptr;
const SPP_Material *cur_mat = nullptr; const SPP_Material *cur_mat = nullptr;
if (ne_child->Type == AMFNodeElementBase::ENET_Volume) { if (ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) {
/******************* Get faces *******************/ /******************* Get faces *******************/
const AMFVolume *ne_volume = reinterpret_cast<const AMFVolume *>(ne_child); const CAMFImporter_NodeElement_Volume *ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume *>(ne_child);
std::list<SComplexFace> complex_faces_list; // List of the faces of the volume. std::list<SComplexFace> complex_faces_list; // List of the faces of the volume.
std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh. std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh.
// check if volume use material // check if volume use material
if (!ne_volume->MaterialID.empty()) { if (!ne_volume->MaterialID.empty()) {
if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) { if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID);
Throw_ID_NotFound(ne_volume->MaterialID);
}
} }
// inside "volume" collect all data and place to arrays or create new objects // inside "volume" collect all data and place to arrays or create new objects
for (const AMFNodeElementBase *ne_volume_child : ne_volume->Child) { for (const CAMFImporter_NodeElement *ne_volume_child : ne_volume->Child) {
// color for volume // color for volume
if (ne_volume_child->Type == AMFNodeElementBase::ENET_Color) { if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color) {
ne_volume_color = reinterpret_cast<const AMFColor *>(ne_volume_child); ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_volume_child);
} else if (ne_volume_child->Type == AMFNodeElementBase::ENET_Triangle) // triangles, triangles colors } else if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle) // triangles, triangles colors
{ {
const AMFTriangle &tri_al = *reinterpret_cast<const AMFTriangle *>(ne_volume_child); const CAMFImporter_NodeElement_Triangle &tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle *>(ne_volume_child);
SComplexFace complex_face; SComplexFace complex_face;
@ -401,11 +388,11 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
complex_face.TexMap = nullptr; complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates. // get data from triangle children: color, texture coordinates.
if (tri_al.Child.size()) { if (tri_al.Child.size()) {
for (const AMFNodeElementBase *ne_triangle_child : tri_al.Child) { for (const CAMFImporter_NodeElement *ne_triangle_child : tri_al.Child) {
if (ne_triangle_child->Type == AMFNodeElementBase::ENET_Color) if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color)
complex_face.Color = reinterpret_cast<const AMFColor *>(ne_triangle_child); complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_triangle_child);
else if (ne_triangle_child->Type == AMFNodeElementBase::ENET_TexMap) else if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const AMFTexMap *>(ne_triangle_child); complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap *>(ne_triangle_child);
} }
} // if(tri_al.Child.size()) } // if(tri_al.Child.size())
@ -429,24 +416,21 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
if (pBiggerThan != nullptr) { if (pBiggerThan != nullptr) {
bool found = false; bool found = false;
const size_t biggerThan = *pBiggerThan;
for (const SComplexFace &face : pFaceList) { for (const SComplexFace &face : pFaceList) {
for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) { for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) {
if (face.Face.mIndices[idx_vert] > biggerThan) { if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
rv = face.Face.mIndices[idx_vert]; rv = face.Face.mIndices[idx_vert];
found = true; found = true;
break; break;
} }
} }
if (found) { if (found) break;
break;
}
} }
if (!found) { if (!found) return *pBiggerThan;
return *pBiggerThan;
}
} else { } else {
rv = pFaceList.front().Face.mIndices[0]; rv = pFaceList.front().Face.mIndices[0];
} // if(pBiggerThan != nullptr) else } // if(pBiggerThan != nullptr) else
@ -521,9 +505,9 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size()); tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
tmesh->mFaces = new aiFace[tmesh->mNumFaces]; tmesh->mFaces = new aiFace[tmesh->mNumFaces];
// Create vertices list and optimize indices. Optimization mean following.In AMF all volumes use one big list of vertices. And one volume // Create vertices list and optimize indices. Optimisation mean following.In AMF all volumes use one big list of vertices. And one volume
// can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10. // can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10.
// Do you need all this thousands of garbage? Of course no. So, optimization step transform sparse indices set to continuous. // Do you need all this thousands of garbage? Of course no. So, optimisation step transformate sparse indices set to continuous.
size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles. size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
std::vector<aiVector3D> vert_arr, texcoord_arr; std::vector<aiVector3D> vert_arr, texcoord_arr;
std::vector<aiColor4D> col_arr; std::vector<aiColor4D> col_arr;
@ -582,7 +566,7 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
size_t idx_vert_new = vert_arr.size(); size_t idx_vert_new = vert_arr.size();
///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for ///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for
/// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
/// optimization. /// optimisation.
bool *idx_vert_used; bool *idx_vert_used;
idx_vert_used = new bool[VertexCount_Max * 2]; idx_vert_used = new bool[VertexCount_Max * 2];
@ -655,15 +639,15 @@ void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const st
} // if(mesh_idx.size() > 0) } // if(mesh_idx.size() > 0)
} }
void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial &pMaterial) { void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material &pMaterial) {
SPP_Material new_mat; SPP_Material new_mat;
new_mat.ID = pMaterial.ID; new_mat.ID = pMaterial.ID;
for (const AMFNodeElementBase *mat_child : pMaterial.Child) { for (const CAMFImporter_NodeElement *mat_child : pMaterial.Child) {
if (mat_child->Type == AMFNodeElementBase::ENET_Color) { if (mat_child->Type == CAMFImporter_NodeElement::ENET_Color) {
new_mat.Color = (AMFColor*)mat_child; new_mat.Color = (CAMFImporter_NodeElement_Color *)mat_child;
} else if (mat_child->Type == AMFNodeElementBase::ENET_Metadata) { } else if (mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata) {
new_mat.Metadata.push_back((AMFMetadata *)mat_child); new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata *)mat_child);
} }
} // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child) } // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
@ -671,7 +655,7 @@ void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial &pMaterial) {
mMaterial_Converted.push_back(new_mat); mMaterial_Converted.push_back(new_mat);
} }
void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const { void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation &pConstellation, std::list<aiNode *> &pNodeList) const {
aiNode *con_node; aiNode *con_node;
std::list<aiNode *> ch_node; std::list<aiNode *> ch_node;
@ -683,18 +667,18 @@ void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellatio
con_node = new aiNode; con_node = new aiNode;
con_node->mName = pConstellation.ID; con_node->mName = pConstellation.ID;
// Walk through children and search for instances of another objects, constellations. // Walk through children and search for instances of another objects, constellations.
for (const AMFNodeElementBase *ne : pConstellation.Child) { for (const CAMFImporter_NodeElement *ne : pConstellation.Child) {
aiMatrix4x4 tmat; aiMatrix4x4 tmat;
aiNode *t_node; aiNode *t_node;
aiNode *found_node; aiNode *found_node;
if (ne->Type == AMFNodeElementBase::ENET_Metadata) continue; if (ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue;
if (ne->Type != AMFNodeElementBase::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>."); if (ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for convenience // create alias for conveniance
AMFInstance &als = *((AMFInstance *)ne); CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne);
// find referenced object // find referenced object
if (!Find_ConvertedNode(als.ObjectID, nodeArray, &found_node)) Throw_ID_NotFound(als.ObjectID); if (!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation // create node for applying transformation
t_node = new aiNode; t_node = new aiNode;
@ -723,13 +707,13 @@ void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellatio
con_node->mChildren[ch_idx++] = node; con_node->mChildren[ch_idx++] = node;
// and place "root" of <constellation> node to node list // and place "root" of <constellation> node to node list
nodeArray.push_back(con_node); pNodeList.push_back(con_node);
} }
void AMFImporter::Postprocess_BuildScene(aiScene *pScene) { void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
NodeArray nodeArray; std::list<aiNode *> node_list;
MeshArray mesh_list; std::list<aiMesh *> mesh_list;
AMFMetaDataArray meta_list; std::list<CAMFImporter_NodeElement_Metadata *> meta_list;
// //
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used. // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
@ -739,21 +723,18 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
pScene->mRootNode->mParent = nullptr; pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED; pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
// search for root(<amf>) element // search for root(<amf>) element
AMFNodeElementBase *root_el = nullptr; CAMFImporter_NodeElement *root_el = nullptr;
for (AMFNodeElementBase *ne : mNodeElement_List) { for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
if (ne->Type != AMFNodeElementBase::ENET_Root) { if (ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
continue;
}
root_el = ne; root_el = ne;
break; break;
} // for(const CAMFImporter_NodeElement* ne: mNodeElement_List) } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found. // Check if root element are found.
if (root_el == nullptr) { if (root_el == nullptr) throw DeadlyImportError("Root(<amf>) element not found.");
throw DeadlyImportError("Root(<amf>) element not found.");
}
// after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>, // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read // <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
@ -761,38 +742,34 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
// //
// 1. <material> // 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet // 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
for (const AMFNodeElementBase *root_child : root_el->Child) { for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
if (root_child->Type == AMFNodeElementBase::ENET_Material) { if (root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material *)root_child));
Postprocess_BuildMaterial(*((AMFMaterial *)root_child));
}
} }
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>. // After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
// //
// 3. <object> // 3. <object>
for (const AMFNodeElementBase *root_child : root_el->Child) { for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
if (root_child->Type == AMFNodeElementBase::ENET_Object) { if (root_child->Type == CAMFImporter_NodeElement::ENET_Object) {
aiNode *tnode = nullptr; aiNode *tnode = nullptr;
// for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance> // for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
Postprocess_BuildNodeAndObject(*((AMFObject *)root_child), mesh_list, &tnode); Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object *)root_child), mesh_list, &tnode);
if (tnode != nullptr) { if (tnode != nullptr) node_list.push_back(tnode);
nodeArray.push_back(tnode);
}
} }
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child) } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes. // And finally read rest of nodes.
// //
for (const AMFNodeElementBase *root_child : root_el->Child) { for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
// 4. <constellation> // 4. <constellation>
if (root_child->Type == AMFNodeElementBase::ENET_Constellation) { if (root_child->Type == CAMFImporter_NodeElement::ENET_Constellation) {
// <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's. // <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's.
Postprocess_BuildConstellation(*((AMFConstellation *)root_child), nodeArray); Postprocess_BuildConstellation(*((CAMFImporter_NodeElement_Constellation *)root_child), node_list);
} }
// 5, <metadata> // 5, <metadata>
if (root_child->Type == AMFNodeElementBase::ENET_Metadata) meta_list.push_back((AMFMetadata *)root_child); if (root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata *)root_child);
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child) } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// at now we can add collected metadata to root node // at now we can add collected metadata to root node
@ -806,18 +783,17 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
// And at this step we are checking that relations. // And at this step we are checking that relations.
nl_clean_loop: nl_clean_loop:
if (nodeArray.size() > 1) { if (node_list.size() > 1) {
// walk through all nodes // walk through all nodes
for (NodeArray::iterator nl_it = nodeArray.begin(); nl_it != nodeArray.end(); ++nl_it) { for (std::list<aiNode *>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) {
// and try to find them in another top nodes. // and try to find them in another top nodes.
NodeArray::const_iterator next_it = nl_it; std::list<aiNode *>::const_iterator next_it = nl_it;
++next_it; ++next_it;
for (; next_it != nodeArray.end(); ++next_it) { for (; next_it != node_list.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 node_list.erase(nl_it);
nodeArray.erase(nl_it);
goto nl_clean_loop; goto nl_clean_loop;
} }
@ -830,10 +806,10 @@ nl_clean_loop:
// //
// //
// Nodes // Nodes
if (!nodeArray.empty()) { if (!node_list.empty()) {
NodeArray::const_iterator nl_it = nodeArray.begin(); std::list<aiNode *>::const_iterator nl_it = node_list.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(nodeArray.size()); pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) { for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) {
// Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have // Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have
@ -846,7 +822,7 @@ nl_clean_loop:
// //
// Meshes // Meshes
if (!mesh_list.empty()) { if (!mesh_list.empty()) {
MeshArray::const_iterator ml_it = mesh_list.begin(); std::list<aiMesh *>::const_iterator ml_it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size()); pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
@ -868,7 +844,7 @@ nl_clean_loop:
pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height); pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data; pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data;
// texture format description. // texture format description.
strncpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint, HINTMAXTEXTURELEN); strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
idx++; idx++;
} // for(const SPP_Texture& tex_convd: mTexture_Converted) } // for(const SPP_Texture& tex_convd: mTexture_Converted)
@ -877,7 +853,7 @@ nl_clean_loop:
pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size()); pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size());
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
for (const SPP_Texture &tex_convd : mTexture_Converted) { for (const SPP_Texture &tex_convd : mTexture_Converted) {
const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + ai_to_string(idx)); const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx));
const int mode = aiTextureOp_Multiply; const int mode = aiTextureOp_Multiply;
const int repeat = tex_convd.Tiled ? 1 : 0; const int repeat = tex_convd.Tiled ? 1 : 0;

View File

@ -3,7 +3,9 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -44,6 +46,7 @@ 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
@ -63,10 +66,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>
namespace Assimp { using namespace Assimp;
using namespace Assimp::ASE; using namespace Assimp::ASE;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"ASE Importer", "ASE Importer",
"", "",
"", "",
@ -86,11 +89,27 @@ ASEImporter::ASEImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ASEImporter::~ASEImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
static const char *tokens[] = { "*3dsmax_asciiexport" }; // check file extension
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); const std::string extension = GetExtension(pFile);
if (extension == "ase" || extension == "ask") {
return true;
}
if ((!extension.length() || cs) && pIOHandler) {
const char *tokens[] = { "*3dsmax_asciiexport" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -117,14 +136,14 @@ void ASEImporter::InternReadFile(const std::string &pFile,
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if (file == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open ASE file ", pFile, "."); throw DeadlyImportError("Failed to open ASE file " + pFile + ".");
} }
// 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
std::vector<char> mBuffer2; std::vector<char> mBuffer2;
TextFileToBuffer(file.get(), mBuffer2); TextFileToBuffer(file.get(), mBuffer2);
const size_t fileSize = mBuffer2.size();
this->mBuffer = &mBuffer2[0]; this->mBuffer = &mBuffer2[0];
this->pcScene = pScene; this->pcScene = pScene;
@ -146,7 +165,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
}; };
// Construct an ASE parser and parse the file // Construct an ASE parser and parse the file
ASE::Parser parser(mBuffer, fileSize, defaultFormat); ASE::Parser parser(mBuffer, defaultFormat);
mParser = &parser; mParser = &parser;
mParser->Parse(); mParser->Parse();
@ -258,7 +277,7 @@ void ASEImporter::GenerateDefaultMaterial() {
} }
if (bHas || mParser->m_vMaterials.empty()) { if (bHas || mParser->m_vMaterials.empty()) {
// add a simple material without submaterials to the parser's list // add a simple material without submaterials to the parser's list
mParser->m_vMaterials.emplace_back(AI_DEFAULT_MATERIAL_NAME); mParser->m_vMaterials.push_back(ASE::Material(AI_DEFAULT_MATERIAL_NAME));
ASE::Material &mat = mParser->m_vMaterials.back(); ASE::Material &mat = mParser->m_vMaterials.back();
mat.mDiffuse = aiColor3D(0.6f, 0.6f, 0.6f); mat.mDiffuse = aiColor3D(0.6f, 0.6f, 0.6f);
@ -321,6 +340,21 @@ 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];
@ -446,9 +480,10 @@ void ASEImporter::BuildLights() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParent, const std::string &name) { void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
aiNode *pcParent, const char *szName) {
aiMatrix4x4 m; aiMatrix4x4 m;
AddNodes(nodes, pcParent, name, m); AddNodes(nodes, pcParent, szName, m);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -505,9 +540,10 @@ void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Add child nodes to a given parent node // Add child nodes to a given parent node
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParent, const std::string &name, void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
aiNode *pcParent, const char *szName,
const aiMatrix4x4 &mat) { const aiMatrix4x4 &mat) {
const size_t len = name.size(); const size_t len = szName ? ::strlen(szName) : 0;
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
// Receives child nodes for the pcParent node // Receives child nodes for the pcParent node
@ -517,18 +553,16 @@ void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParen
// which has *us* as parent. // which has *us* as parent.
for (std::vector<BaseNode *>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) { for (std::vector<BaseNode *>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
const BaseNode *snode = *it; const BaseNode *snode = *it;
if (!name.empty()) { if (szName) {
if (len != snode->mParent.length() || name != snode->mParent.c_str()) { if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str()))
continue; continue;
} } else if (snode->mParent.length())
} else if (snode->mParent.length()) {
continue; continue;
}
(*it)->mProcessed = true; (*it)->mProcessed = true;
// Allocate a new node and add it to the output data structure // Allocate a new node and add it to the output data structure
apcNodes.push_back(new aiNode); apcNodes.push_back(new aiNode());
aiNode *node = apcNodes.back(); aiNode *node = apcNodes.back();
node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node")); node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
@ -541,7 +575,7 @@ void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParen
// Add sub nodes - prevent stack overflow due to recursive parenting // Add sub nodes - prevent stack overflow due to recursive parenting
if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) { if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) {
AddNodes(nodes, node, node->mName.C_Str(), snode->mTransform); AddNodes(nodes, node, node->mName.data, snode->mTransform);
} }
// Further processing depends on the type of the node // Further processing depends on the type of the node
@ -580,7 +614,7 @@ void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParen
node->mNumChildren++; node->mNumChildren++;
// What we did is so great, it is at least worth a debug message // What we did is so great, it is at least worth a debug message
ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (", snode->mName, ")"); ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (" + snode->mName + ")");
} }
} }
@ -619,8 +653,7 @@ void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
} }
// add all nodes // add all nodes
static const std::string none = ""; AddNodes(nodes, ch, nullptr);
AddNodes(nodes, ch, none);
// now iterate through al nodes and find those that have not yet // now iterate through al nodes and find those that have not yet
// been added to the nodegraph (= their parent could not be recognized) // been added to the nodegraph (= their parent could not be recognized)
@ -650,7 +683,7 @@ void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
} }
} }
// Are there any orphaned nodes? // Are there ane orphaned nodes?
if (!aiList.empty()) { if (!aiList.empty()) {
std::vector<aiNode *> apcNodes; std::vector<aiNode *> apcNodes;
apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren); apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
@ -849,7 +882,6 @@ void ASEImporter::ConvertMaterial(ASE::Material &mat) {
unsigned int iWire = 1; unsigned int iWire = 1;
mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME); mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
} }
// fallthrough
case D3DS::Discreet3DS::Gouraud: case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; eShading = aiShadingMode_Gouraud;
break; break;
@ -905,7 +937,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 consists of submeshes, split it // If the material the mesh is assigned to is consisting 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;
@ -984,8 +1016,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMes
blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end(); ++blubb) { blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end(); ++blubb) {
// NOTE: illegal cases have already been filtered out // NOTE: illegal cases have already been filtered out
avOutputBones[(*blubb).first].emplace_back( avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>(
iBase, (*blubb).second); iBase, (*blubb).second));
} }
} }
} }
@ -1263,8 +1295,6 @@ 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

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -62,37 +62,42 @@ namespace Assimp {
class ASEImporter : public BaseImporter { class ASEImporter : public BaseImporter {
public: public:
ASEImporter(); ASEImporter();
~ASEImporter() override = default; ~ASEImporter();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** 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;
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
*/ */
const aiImporterDesc* GetInfo () const override; const aiImporterDesc* GetInfo () const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Imports the given file into the given scene structure. /** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details * See BaseImporter::InternReadFile() for details
*/ */
void InternReadFile( const std::string& pFile, aiScene* pScene, void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler) override; IOSystem* pIOHandler);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ReadFile(). /** Called prior to ReadFile().
* The function is a request to the importer to update its configuration * The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
void SetupProperties(const Importer* pImp) override; void SetupProperties(const Importer* pImp);
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Generate normal vectors basing on smoothing groups /** Generate normal vectors basing on smoothing groups
* (in some cases the normal are already contained in the file) * (in some cases the normal are already contained in the file)
@ -101,6 +106,7 @@ private:
*/ */
bool GenerateNormals(ASE::Mesh& mesh); bool GenerateNormals(ASE::Mesh& mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Create valid vertex/normal/UV/color/face lists. /** Create valid vertex/normal/UV/color/face lists.
* All elements are unique, faces have only one set of indices * All elements are unique, faces have only one set of indices
@ -109,43 +115,51 @@ private:
*/ */
void BuildUniqueRepresentation(ASE::Mesh& mesh); void BuildUniqueRepresentation(ASE::Mesh& mesh);
/** Create one-material-per-mesh meshes ;-) /** Create one-material-per-mesh meshes ;-)
* \param mesh Mesh to work with * \param mesh Mesh to work with
* \param Receives the list of all created meshes * \param Receives the list of all created meshes
*/ */
void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut); void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Convert a material to a aiMaterial object /** Convert a material to a aiMaterial object
* \param mat Input material * \param mat Input material
*/ */
void ConvertMaterial(ASE::Material& mat); void ConvertMaterial(ASE::Material& mat);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Setup the final material indices for each mesh /** Setup the final material indices for each mesh
*/ */
void BuildMaterialIndices(); void BuildMaterialIndices();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build the node graph /** Build the node graph
*/ */
void BuildNodes(std::vector<ASE::BaseNode*>& nodes); void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build output cameras /** Build output cameras
*/ */
void BuildCameras(); void BuildCameras();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build output lights /** Build output lights
*/ */
void BuildLights(); void BuildLights();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build output animations /** Build output animations
*/ */
void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes); void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Add sub nodes to a node /** Add sub nodes to a node
* \param pcParent parent node to be filled * \param pcParent parent node to be filled
@ -153,13 +167,13 @@ private:
* \param matrix Current transform * \param matrix Current transform
*/ */
void AddNodes(const std::vector<ASE::BaseNode*>& nodes, void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
aiNode* pcParent, const std::string &name); aiNode* pcParent,const char* szName);
void AddNodes(const std::vector<ASE::BaseNode*>& nodes, void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
aiNode* pcParent, const std::string &name, aiNode* pcParent,const char* szName,
const aiMatrix4x4& matrix); const aiMatrix4x4& matrix);
void AddMeshes(const ASE::BaseNode* snode, aiNode* node); void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Generate a default material and add it to the parser's list /** Generate a default material and add it to the parser's list
@ -169,6 +183,7 @@ private:
void GenerateDefaultMaterial(); void GenerateDefaultMaterial();
protected: protected:
/** Parser instance */ /** Parser instance */
ASE::Parser* mParser; ASE::Parser* mParser;
@ -188,4 +203,5 @@ protected:
} // end of namespace Assimp } // end of namespace Assimp
#endif // AI_3DSIMPORTER_H_INC #endif // AI_3DSIMPORTER_H_INC

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -94,8 +95,8 @@ struct Material : public D3DS::Material {
Material(Material &&other) AI_NO_EXCEPT Material(Material &&other) AI_NO_EXCEPT
: D3DS::Material(std::move(other)), : D3DS::Material(std::move(other)),
avSubMaterials(std::move(other.avSubMaterials)), avSubMaterials(std::move(other.avSubMaterials)),
pcInstance(other.pcInstance), pcInstance(std::move(other.pcInstance)),
bNeed(other.bNeed) { bNeed(std::move(other.bNeed)) {
other.pcInstance = nullptr; other.pcInstance = nullptr;
} }
@ -107,15 +108,15 @@ struct Material : public D3DS::Material {
//D3DS::Material::operator=(std::move(other)); //D3DS::Material::operator=(std::move(other));
avSubMaterials = std::move(other.avSubMaterials); avSubMaterials = std::move(other.avSubMaterials);
pcInstance = other.pcInstance; pcInstance = std::move(other.pcInstance);
bNeed = other.bNeed; bNeed = std::move(other.bNeed);
other.pcInstance = nullptr; other.pcInstance = nullptr;
return *this; return *this;
} }
~Material() = default; ~Material() {}
//! Contains all sub materials of this material //! Contains all sub materials of this material
std::vector<Material> avSubMaterials; std::vector<Material> avSubMaterials;
@ -384,18 +385,20 @@ struct Dummy : public BaseNode {
/** \brief Class to parse ASE files /** \brief Class to parse ASE files
*/ */
class Parser { class Parser {
public: private:
/// @brief No default constructor. Parser() AI_NO_EXCEPT {
Parser() = delete; // empty
}
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Construct a parser from a given input file which is //! Construct a parser from a given input file which is
//! guaranteed to be terminated with zero. //! guaranteed to be terminated with zero.
//! @param file The name of the input file. //! @param szFile Input file
//! @param fileFormatDefault Assumed file format version. If the //! @param fileFormatDefault Assumed file format version. If the
//! file format is specified in the file the new value replaces //! file format is specified in the file the new value replaces
//! the default value. //! the default value.
Parser(const char *file, size_t fileLen, unsigned int fileFormatDefault); Parser(const char *szFile, unsigned int fileFormatDefault);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parses the file into the parsers internal representation //! Parses the file into the parsers internal representation
@ -553,15 +556,13 @@ private:
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats) //! \param apOut Output buffer (3 floats)
//! \param rIndexOut Output index //! \param rIndexOut Output index
void ParseLV4MeshRealTriple(ai_real *apOut, unsigned int &rIndexOut); void ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut);
void ParseLV4MeshFloatTriple(float *apOut, unsigned int &rIndexOut);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a *MESH_VERT block in a file //! Parse a *MESH_VERT block in a file
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats) //! \param apOut Output buffer (3 floats)
void ParseLV4MeshRealTriple(ai_real *apOut); void ParseLV4MeshFloatTriple(ai_real *apOut);
void ParseLV4MeshFloatTriple(float *apOut);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a *MESH_TFACE block in a file //! Parse a *MESH_TFACE block in a file
@ -579,8 +580,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a single float element //! Parse a single float element
//! \param fOut Output float //! \param fOut Output float
void ParseLV4MeshReal(ai_real &fOut); void ParseLV4MeshFloat(ai_real &fOut);
void ParseLV4MeshFloat(float &fOut);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a single int element //! Parse a single int element
@ -620,8 +620,8 @@ private:
bool ParseString(std::string &out, const char *szName); bool ParseString(std::string &out, const char *szName);
public: public:
const char *mFilePtr; ////< Pointer to current data //! Pointer to current data
const char *mEnd; ///< The end pointer of the file data const char *filePtr;
//! background color to be passed to the viewer //! background color to be passed to the viewer
//! QNAN if none was found //! QNAN if none was found

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,19 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file AssbinExporter.h /** @file AssbinExporter.h
* ASSBIN Exporter Main Header * ASSBIN Exporter Main Header
*/ */
#pragma once
#ifndef AI_ASSBINEXPORTER_H_INC #ifndef AI_ASSBINEXPORTER_H_INC
#define AI_ASSBINEXPORTER_H_INC #define AI_ASSBINEXPORTER_H_INC
#include <assimp/defs.h> #include <assimp/defs.h>
#ifndef ASSIMP_BUILD_NO_EXPORT
// nothing really needed here - reserved for future use like properties // nothing really needed here - reserved for future use like properties
namespace Assimp { namespace Assimp {
void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/); void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/);
} }
#endif
#endif // AI_ASSBINEXPORTER_H_INC #endif // AI_ASSBINEXPORTER_H_INC

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -43,21 +43,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "AssbinFileWriter.h" #include "AssbinFileWriter.h"
#include "Common/assbin_chunks.h" #include "Common/assbin_chunks.h"
#include "PostProcessing/ProcessHelper.h" #include "PostProcessing/ProcessHelper.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/version.h> #include <assimp/version.h>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include "zlib.h" #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif
#include <ctime> #include <time.h>
#if _MSC_VER #ifdef _WIN32
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4706) #pragma warning(disable : 4706)
#endif // _MSC_VER #endif // _WIN32
namespace Assimp { namespace Assimp {
@ -126,7 +132,7 @@ inline size_t Write<double>(IOStream *stream, const double &f) {
// Serialize a vec3 // Serialize a vec3
template <> template <>
inline size_t Write<aiVector3D>(IOStream *stream, const aiVector3D &v) { inline size_t Write<aiVector3D>(IOStream *stream, const aiVector3D &v) {
size_t t = Write<ai_real>(stream, v.x); size_t t = Write<float>(stream, v.x);
t += Write<float>(stream, v.y); t += Write<float>(stream, v.y);
t += Write<float>(stream, v.z); t += Write<float>(stream, v.z);
@ -137,7 +143,7 @@ inline size_t Write<aiVector3D>(IOStream *stream, const aiVector3D &v) {
// Serialize a color value // Serialize a color value
template <> template <>
inline size_t Write<aiColor3D>(IOStream *stream, const aiColor3D &v) { inline size_t Write<aiColor3D>(IOStream *stream, const aiColor3D &v) {
size_t t = Write<ai_real>(stream, v.r); size_t t = Write<float>(stream, v.r);
t += Write<float>(stream, v.g); t += Write<float>(stream, v.g);
t += Write<float>(stream, v.b); t += Write<float>(stream, v.b);
@ -148,7 +154,7 @@ inline size_t Write<aiColor3D>(IOStream *stream, const aiColor3D &v) {
// Serialize a color value // Serialize a color value
template <> template <>
inline size_t Write<aiColor4D>(IOStream *stream, const aiColor4D &v) { inline size_t Write<aiColor4D>(IOStream *stream, const aiColor4D &v) {
size_t t = Write<ai_real>(stream, v.r); size_t t = Write<float>(stream, v.r);
t += Write<float>(stream, v.g); t += Write<float>(stream, v.g);
t += Write<float>(stream, v.b); t += Write<float>(stream, v.b);
t += Write<float>(stream, v.a); t += Write<float>(stream, v.a);
@ -160,13 +166,13 @@ inline size_t Write<aiColor4D>(IOStream *stream, const aiColor4D &v) {
// Serialize a quaternion // Serialize a quaternion
template <> template <>
inline size_t Write<aiQuaternion>(IOStream *stream, const aiQuaternion &v) { inline size_t Write<aiQuaternion>(IOStream *stream, const aiQuaternion &v) {
size_t t = Write<ai_real>(stream, v.w); size_t t = Write<float>(stream, v.w);
t += Write<float>(stream, v.x); t += Write<float>(stream, v.x);
t += Write<float>(stream, v.y); t += Write<float>(stream, v.y);
t += Write<float>(stream, v.z); t += Write<float>(stream, v.z);
ai_assert(t == 16); ai_assert(t == 16);
return t; return 16;
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
@ -178,19 +184,17 @@ inline size_t Write<aiVertexWeight>(IOStream *stream, const aiVertexWeight &v) {
return t + Write<float>(stream, v.mWeight); return t + Write<float>(stream, v.mWeight);
} }
constexpr size_t MatrixSize = 64;
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Serialize a mat4x4 // Serialize a mat4x4
template <> template <>
inline size_t Write<aiMatrix4x4>(IOStream *stream, const aiMatrix4x4 &m) { inline size_t Write<aiMatrix4x4>(IOStream *stream, const aiMatrix4x4 &m) {
for (unsigned int i = 0; i < 4; ++i) { for (unsigned int i = 0; i < 4; ++i) {
for (unsigned int i2 = 0; i2 < 4; ++i2) { for (unsigned int i2 = 0; i2 < 4; ++i2) {
Write<ai_real>(stream, m[i][i2]); Write<float>(stream, m[i][i2]);
} }
} }
return MatrixSize; return 64;
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
@ -273,7 +277,7 @@ public:
// empty // empty
} }
~AssbinChunkWriter() override { virtual ~AssbinChunkWriter() {
if (container) { if (container) {
container->Write(&magic, sizeof(uint32_t), 1); container->Write(&magic, sizeof(uint32_t), 1);
container->Write(&cursor, sizeof(uint32_t), 1); container->Write(&cursor, sizeof(uint32_t), 1);
@ -284,27 +288,26 @@ public:
void *GetBufferPointer() { return buffer; } void *GetBufferPointer() { return buffer; }
size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { // -------------------------------------------------------------------
virtual size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
return 0; return 0;
} }
virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) override {
return aiReturn_FAILURE; return aiReturn_FAILURE;
} }
virtual size_t Tell() const {
size_t Tell() const override {
return cursor; return cursor;
} }
virtual void Flush() {
void Flush() override {
// not implemented // not implemented
} }
size_t FileSize() const override { virtual size_t FileSize() const {
return cursor; return cursor;
} }
size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override { // -------------------------------------------------------------------
virtual size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) {
pSize *= pCount; pSize *= pCount;
if (cursor + pSize > cur_size) { if (cursor + pSize > cur_size) {
Grow(cursor + pSize); Grow(cursor + pSize);
@ -638,10 +641,6 @@ protected:
Write<aiString>(&chunk, l->mName); Write<aiString>(&chunk, l->mName);
Write<unsigned int>(&chunk, l->mType); Write<unsigned int>(&chunk, l->mType);
Write<aiVector3D>(&chunk, l->mPosition);
Write<aiVector3D>(&chunk, l->mDirection);
Write<aiVector3D>(&chunk, l->mUp);
if (l->mType != aiLightSource_DIRECTIONAL) { if (l->mType != aiLightSource_DIRECTIONAL) {
Write<float>(&chunk, l->mAttenuationConstant); Write<float>(&chunk, l->mAttenuationConstant);
Write<float>(&chunk, l->mAttenuationLinear); Write<float>(&chunk, l->mAttenuationLinear);
@ -826,8 +825,8 @@ void DumpSceneToAssbin(
AssbinFileWriter fileWriter(shortened, compressed); AssbinFileWriter fileWriter(shortened, compressed);
fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
} }
#if _MSC_VER #ifdef _WIN32
#pragma warning(pop) #pragma warning(pop)
#endif // _MSC_VER #endif // _WIN32
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -65,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"Assimp Binary Importer", "Assimp Binary Importer",
"Gargaj / Conspiracy", "Gargaj / Conspiracy",
"", "",
@ -406,7 +406,7 @@ void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
f.mIndices = new unsigned int[f.mNumIndices]; f.mIndices = new unsigned int[f.mNumIndices];
for (unsigned int a = 0; a < f.mNumIndices; ++a) { for (unsigned int a = 0; a < f.mNumIndices; ++a) {
// Check if unsigned short ( 16 bit ) are big enough for the indices // Check if unsigned short ( 16 bit ) are big enought for the indices
if (fitsIntoUI16(mesh->mNumVertices)) { if (fitsIntoUI16(mesh->mNumVertices)) {
f.mIndices[a] = Read<uint16_t>(stream); f.mIndices[a] = Read<uint16_t>(stream);
} else { } else {
@ -556,10 +556,6 @@ void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) {
l->mName = Read<aiString>(stream); l->mName = Read<aiString>(stream);
l->mType = (aiLightSourceType)Read<unsigned int>(stream); l->mType = (aiLightSourceType)Read<unsigned int>(stream);
l->mPosition = Read<aiVector3D>(stream);
l->mDirection = Read<aiVector3D>(stream);
l->mUp = Read<aiVector3D>(stream);
if (l->mType != aiLightSource_DIRECTIONAL) { if (l->mType != aiLightSource_DIRECTIONAL) {
l->mAttenuationConstant = Read<float>(stream); l->mAttenuationConstant = Read<float>(stream);
l->mAttenuationLinear = Read<float>(stream); l->mAttenuationLinear = Read<float>(stream);
@ -675,7 +671,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
IOStream *stream = pIOHandler->Open(pFile, "rb"); IOStream *stream = pIOHandler->Open(pFile, "rb");
if (nullptr == stream) { if (nullptr == stream) {
throw DeadlyImportError("ASSBIN: Could not open ", pFile); return;
} }
// signature // signature

View File

@ -3,7 +3,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -73,11 +74,17 @@ private:
bool compressed; bool compressed;
public: public:
bool CanRead(const std::string& pFile, virtual bool CanRead(
IOSystem* pIOHandler, bool checkSig) const override; const std::string& pFile,
const aiImporterDesc* GetInfo() const override; IOSystem* pIOHandler,
void InternReadFile( bool checkSig
const std::string& pFile,aiScene* pScene,IOSystem* pIOHandler) override; ) const;
virtual const aiImporterDesc* GetInfo() const;
virtual void InternReadFile(
const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
);
void ReadHeader(); void ReadHeader();
void ReadBinaryScene( IOStream * stream, aiScene* pScene ); void ReadBinaryScene( IOStream * stream, aiScene* pScene );
void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent ); void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent );

View File

@ -7,12 +7,10 @@ For details, see http://sourceforge.net/projects/libb64
#include "cencode.h" // changed from <B64/cencode.h> #include "cencode.h" // changed from <B64/cencode.h>
static const int CHARS_PER_LINE = 72; const int CHARS_PER_LINE = 72;
#ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4244) #pragma warning(disable : 4244)
#endif // _MSC_VER
void base64_init_encodestate(base64_encodestate* state_in) void base64_init_encodestate(base64_encodestate* state_in)
{ {
@ -112,6 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
return (int)(codechar - code_out); return (int)(codechar - code_out);
} }
#ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif // _MSC_VER

View File

@ -8,9 +8,9 @@ For details, see http://sourceforge.net/projects/libb64
#ifndef BASE64_CENCODE_H #ifndef BASE64_CENCODE_H
#define BASE64_CENCODE_H #define BASE64_CENCODE_H
#ifdef _MSC_VER #ifdef _WIN32
#pragma warning(disable : 4127 ) #pragma warning(disable : 4127 )
#endif // _MSC_VER #endif // _WIN32
typedef enum typedef enum
{ {

View File

@ -10,7 +10,6 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/ai_assert.h>
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
@ -24,15 +23,16 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#define CURRENT_FORMAT_VERSION 100 #define CURRENT_FORMAT_VERSION 100
// grab scoped_ptr from assimp to avoid a dependency on boost.
//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
#include "mesh_splitter.h" #include "mesh_splitter.h"
extern "C" { extern "C" {
# include "cencode.h" #include "cencode.h"
} }
namespace Assimp { namespace Assimp {
// Forward declarations
void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *); void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
// small utility class to simplify serializing the aiScene to Json // small utility class to simplify serializing the aiScene to Json
@ -41,17 +41,12 @@ public:
enum { enum {
Flag_DoNotIndent = 0x1, Flag_DoNotIndent = 0x1,
Flag_WriteSpecialFloats = 0x2, Flag_WriteSpecialFloats = 0x2,
Flag_SkipWhitespaces = 0x4
}; };
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) : JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
out(out), indent (""), newline("\n"), space(" "), buff (), first(false), flags(flags) { out(out), first(), flags(flags) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale // make sure that all formatting happens using the standard, C locale and not the user's current locale
buff.imbue(std::locale("C")); buff.imbue(std::locale("C"));
if (flags & Flag_SkipWhitespaces) {
newline = "";
space = "";
}
} }
~JSONWriter() { ~JSONWriter() {
@ -75,7 +70,7 @@ public:
void Key(const std::string &name) { void Key(const std::string &name) {
AddIndentation(); AddIndentation();
Delimit(); Delimit();
buff << '\"' + name + "\":" << space; buff << '\"' + name + "\": ";
} }
template <typename Literal> template <typename Literal>
@ -83,12 +78,12 @@ public:
AddIndentation(); AddIndentation();
Delimit(); Delimit();
LiteralToString(buff, name) << newline; LiteralToString(buff, name) << '\n';
} }
template <typename Literal> template <typename Literal>
void SimpleValue(const Literal &s) { void SimpleValue(const Literal &s) {
LiteralToString(buff, s) << newline; LiteralToString(buff, s) << '\n';
} }
void SimpleValue(const void *buffer, size_t len) { void SimpleValue(const void *buffer, size_t len) {
@ -107,7 +102,7 @@ public:
} }
} }
buff << '\"' << cur_out << "\"" << newline; buff << '\"' << cur_out << "\"\n";
delete[] cur_out; delete[] cur_out;
} }
@ -120,7 +115,7 @@ public:
} }
} }
first = true; first = true;
buff << "{" << newline; buff << "{\n";
PushIndent(); PushIndent();
} }
@ -128,7 +123,7 @@ public:
PopIndent(); PopIndent();
AddIndentation(); AddIndentation();
first = false; first = false;
buff << "}" << newline; buff << "}\n";
} }
void StartArray(bool is_element = false) { void StartArray(bool is_element = false) {
@ -140,19 +135,19 @@ public:
} }
} }
first = true; first = true;
buff << "[" << newline; buff << "[\n";
PushIndent(); PushIndent();
} }
void EndArray() { void EndArray() {
PopIndent(); PopIndent();
AddIndentation(); AddIndentation();
buff << "]" << newline; buff << "]\n";
first = false; first = false;
} }
void AddIndentation() { void AddIndentation() {
if (!(flags & Flag_DoNotIndent) && !(flags & Flag_SkipWhitespaces)) { if (!(flags & Flag_DoNotIndent)) {
buff << indent; buff << indent;
} }
} }
@ -161,7 +156,7 @@ public:
if (!first) { if (!first) {
buff << ','; buff << ',';
} else { } else {
buff << space; buff << ' ';
first = false; first = false;
} }
} }
@ -179,6 +174,7 @@ private:
// escape backslashes and single quotes, both would render the JSON invalid if left as is // escape backslashes and single quotes, both would render the JSON invalid if left as is
t.reserve(s.length); t.reserve(s.length);
for (size_t i = 0; i < s.length; ++i) { for (size_t i = 0; i < s.length; ++i) {
if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') { if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') {
t.push_back('\\'); t.push_back('\\');
} }
@ -231,16 +227,14 @@ private:
private: private:
Assimp::IOStream &out; Assimp::IOStream &out;
std::string indent; std::string indent, newline;
std::string newline;
std::string space;
std::stringstream buff; std::stringstream buff;
bool first; bool first;
unsigned int flags; unsigned int flags;
}; };
static void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.x); out.Element(ai.x);
out.Element(ai.y); out.Element(ai.y);
@ -248,7 +242,7 @@ static void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
static void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.w); out.Element(ai.w);
out.Element(ai.x); out.Element(ai.x);
@ -257,7 +251,7 @@ static void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true)
out.EndArray(); out.EndArray();
} }
static void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.r); out.Element(ai.r);
out.Element(ai.g); out.Element(ai.g);
@ -265,7 +259,7 @@ static void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
static void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
for (unsigned int x = 0; x < 4; ++x) { for (unsigned int x = 0; x < 4; ++x) {
for (unsigned int y = 0; y < 4; ++y) { for (unsigned int y = 0; y < 4; ++y) {
@ -275,7 +269,7 @@ static void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
static void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -296,7 +290,7 @@ static void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
for (unsigned int i = 0; i < ai.mNumIndices; ++i) { for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
out.Element(ai.mIndices[i]); out.Element(ai.mIndices[i]);
@ -304,7 +298,7 @@ static void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
static void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -415,7 +409,7 @@ static void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -445,7 +439,7 @@ static void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("properties"); out.Key("properties");
@ -476,17 +470,7 @@ static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
out.SimpleValue(*reinterpret_cast<float *>(prop->mData)); out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
} }
break; break;
case aiPTI_Double:
if (prop->mDataLength / sizeof(double) > 1) {
out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(double); ++ii) {
out.Element(reinterpret_cast<double*>(prop->mData)[ii]);
}
out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<double*>(prop->mData));
}
break;
case aiPTI_Integer: case aiPTI_Integer:
if (prop->mDataLength / sizeof(int) > 1) { if (prop->mDataLength / sizeof(int) > 1) {
out.StartArray(); out.StartArray();
@ -499,21 +483,17 @@ static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
} }
break; break;
case aiPTI_String: case aiPTI_String: {
{
aiString s; aiString s;
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
out.SimpleValue(s); out.SimpleValue(s);
} } break;
break; case aiPTI_Buffer: {
case aiPTI_Buffer:
{
// binary data is written as series of hex-encoded octets // binary data is written as series of hex-encoded octets
out.SimpleValue(prop->mData, prop->mDataLength); out.SimpleValue(prop->mData, prop->mDataLength);
} } break;
break;
default: default:
ai_assert(false); assert(false);
} }
out.EndObj(); out.EndObj();
@ -523,7 +503,7 @@ static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("width"); out.Key("width");
@ -559,7 +539,7 @@ static void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -607,7 +587,7 @@ static void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -660,7 +640,7 @@ static void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -681,7 +661,7 @@ static void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) { void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -708,7 +688,7 @@ static void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
static void WriteFormatInfo(JSONWriter &out) { void WriteFormatInfo(JSONWriter &out) {
out.StartObj(); out.StartObj();
out.Key("format"); out.Key("format");
out.SimpleValue("\"assimp2json\""); out.SimpleValue("\"assimp2json\"");
@ -717,7 +697,7 @@ static void WriteFormatInfo(JSONWriter &out) {
out.EndObj(); out.EndObj();
} }
static void Write(JSONWriter &out, const aiScene &ai) { void Write(JSONWriter &out, const aiScene &ai) {
out.StartObj(); out.StartObj();
out.Key("__metadata__"); out.Key("__metadata__");
@ -785,7 +765,7 @@ static void Write(JSONWriter &out, const aiScene &ai) {
out.EndObj(); out.EndObj();
} }
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *pProperties) { void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt")); std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
if (!str) { if (!str) {
throw DeadlyExportError("could not open output file"); throw DeadlyExportError("could not open output file");
@ -802,12 +782,7 @@ void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *sc
splitter.Execute(scenecopy_tmp); splitter.Execute(scenecopy_tmp);
// XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
unsigned int flags = JSONWriter::Flag_WriteSpecialFloats;
if (pProperties->GetPropertyBool("JSON_SKIP_WHITESPACES", false)) {
flags |= JSONWriter::Flag_SkipWhitespaces;
}
JSONWriter s(*str, flags);
Write(s, *scenecopy_tmp); Write(s, *scenecopy_tmp);
} catch (...) { } catch (...) {

View File

@ -69,12 +69,13 @@ void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh
for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) { for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) {
UpdateNode ( pcNode->mChildren[i], source_mesh_map ); UpdateNode ( pcNode->mChildren[i], source_mesh_map );
} }
return;
} }
static const unsigned int WAS_NOT_COPIED = 0xffffffff; #define WAS_NOT_COPIED 0xffffffff
using PerVertexWeight = std::pair <unsigned int,float>; typedef std::pair <unsigned int,float> PerVertexWeight;
using VertexWeightTable = std::vector <PerVertexWeight>; typedef std::vector <PerVertexWeight> VertexWeightTable;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) { VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) {
@ -88,7 +89,7 @@ VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) {
aiBone* bone = pMesh->mBones[i]; aiBone* bone = pMesh->mBones[i];
for (unsigned int a = 0; a < bone->mNumWeights;++a) { for (unsigned int a = 0; a < bone->mNumWeights;++a) {
const aiVertexWeight& weight = bone->mWeights[a]; const aiVertexWeight& weight = bone->mWeights[a];
avPerVertexWeights[weight.mVertexId].emplace_back(i,weight.mWeight); avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) );
} }
} }
return avPerVertexWeights; return avPerVertexWeights;
@ -99,7 +100,7 @@ void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std:
// TODO: should better use std::(multi)set for source_mesh_map. // TODO: should better use std::(multi)set for source_mesh_map.
if (in_mesh->mNumVertices <= LIMIT) { if (in_mesh->mNumVertices <= LIMIT) {
source_mesh_map.emplace_back(in_mesh,a); source_mesh_map.push_back(std::make_pair(in_mesh,a));
return; return;
} }
@ -186,7 +187,7 @@ void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std:
break; break;
} }
vFaces.emplace_back(); vFaces.push_back(aiFace());
aiFace& rFace = vFaces.back(); aiFace& rFace = vFaces.back();
// setup face type and number of indices // setup face type and number of indices
@ -304,7 +305,7 @@ void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std:
} }
// add the newly created mesh to the list // add the newly created mesh to the list
source_mesh_map.emplace_back(out_mesh,a); source_mesh_map.push_back(std::make_pair(out_mesh,a));
if (base == in_mesh->mNumFaces) { if (base == in_mesh->mNumFaces) {
break; break;

View File

@ -24,9 +24,10 @@ struct aiNode;
/** Splits meshes of unique vertices into meshes with no more vertices than /** Splits meshes of unique vertices into meshes with no more vertices than
* a given, configurable threshold value. * a given, configurable threshold value.
*/ */
class MeshSplitter { class MeshSplitter
{
public: public:
unsigned int LIMIT;
void SetLimit(unsigned int l) { void SetLimit(unsigned int l) {
LIMIT = l; LIMIT = l;
@ -36,17 +37,25 @@ public:
return LIMIT; return LIMIT;
} }
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute(aiScene *pScene); void Execute( aiScene* pScene);
private: private:
void UpdateNode(aiNode *pcNode, const std::vector<std::pair<aiMesh *, unsigned int>> &source_mesh_map);
void SplitMesh(unsigned int index, aiMesh *mesh, std::vector<std::pair<aiMesh *, unsigned int>> &source_mesh_map);
void UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
void SplitMesh (unsigned int index, aiMesh* mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
public:
unsigned int LIMIT;
}; };
#endif // INCLUDED_MESH_SPLITTER #endif // INCLUDED_MESH_SPLITTER

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file AssxmlExporter.h /** @file AssxmlExporter.h
* ASSXML Exporter Main Header * ASSXML Exporter Main Header
*/ */
#pragma once
#ifndef AI_ASSXMLEXPORTER_H_INC #ifndef AI_ASSXMLEXPORTER_H_INC
#define AI_ASSXMLEXPORTER_H_INC #define AI_ASSXMLEXPORTER_H_INC

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -168,7 +168,7 @@ static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Some chunks of text will need to be encoded for XML // Some chuncks of text will need to be encoded for XML
// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 // http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
static std::string encodeXML(const std::string &data) { static std::string encodeXML(const std::string &data) {
std::string buffer; std::string buffer;
@ -365,7 +365,7 @@ static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene,
ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"", ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
prop->mKey.data, sz, prop->mKey.data, sz,
::aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex); ::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
if (prop->mType == aiPTI_Float) { if (prop->mType == aiPTI_Float) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t", ioprintf(io, " size=\"%i\">\n\t\t\t\t",
@ -598,11 +598,8 @@ static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene,
if (!mesh->mTextureCoords[a]) if (!mesh->mTextureCoords[a])
break; break;
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" name=\"%s\" num_components=\"%u\"> \n", ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" num_components=\"%u\"> \n", mesh->mNumVertices,
mesh->mNumVertices, a, mesh->mNumUVComponents[a]);
a,
(mesh->HasTextureCoordsName(a) ? mesh->GetTextureCoordsName(a)->C_Str() : ""),
mesh->mNumUVComponents[a]);
if (!shortened) { if (!shortened) {
if (mesh->mNumUVComponents[a] == 3) { if (mesh->mNumUVComponents[a] == 3) {
@ -652,7 +649,7 @@ void DumpSceneToAssxml(
const char *pFile, const char *cmd, IOSystem *pIOSystem, const char *pFile, const char *cmd, IOSystem *pIOSystem,
const aiScene *pScene, bool shortened) { const aiScene *pScene, bool shortened) {
std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt")); std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt"));
if (!file) { if (!file.get()) {
throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
} }

View File

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file AssxmlFileWriter.h /** @file AssxmlFileWriter.h
* @brief Declaration of Assxml file writer. * @brief Declaration of Assxml file writer.
*/ */
#pragma once
#ifndef AI_ASSXMLFILEWRITER_H_INC #ifndef AI_ASSXMLFILEWRITER_H_INC
#define AI_ASSXMLFILEWRITER_H_INC #define AI_ASSXMLFILEWRITER_H_INC

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -59,10 +59,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
namespace Assimp { using namespace Assimp;
using namespace std; using namespace std;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"BlitzBasic 3D Importer", "BlitzBasic 3D Importer",
"", "",
"", "",
@ -79,7 +79,7 @@ static constexpr 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) {
@ -88,10 +88,12 @@ void DeleteAllBarePointers(std::vector<T> &x) {
} }
} }
B3DImporter::~B3DImporter() = default; B3DImporter::~B3DImporter() {
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
size_t pos = pFile.find_last_of('.'); size_t pos = pFile.find_last_of('.');
if (pos == string::npos) { if (pos == string::npos) {
return false; return false;
@ -116,8 +118,8 @@ void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
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.get() == nullptr) {
throw DeadlyImportError("Failed to open B3D file ", pFile, "."); throw DeadlyImportError("Failed to open B3D file " + pFile + ".");
} }
// check whether the .b3d file is large enough to contain // check whether the .b3d file is large enough to contain
@ -141,16 +143,16 @@ AI_WONT_RETURN void B3DImporter::Oops() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail(const string &str) { AI_WONT_RETURN void B3DImporter::Fail(string str) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_ERROR("Error in B3D file data: ", str); ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
#endif #endif
throw DeadlyImportError("B3D Importer - error in B3D file data: ", str); throw DeadlyImportError("B3D Importer - error in B3D file data: " + str);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte() { int B3DImporter::ReadByte() {
if (_pos >= _buf.size()) { if (_pos > _buf.size()) {
Fail("EOF"); Fail("EOF");
} }
@ -231,7 +233,7 @@ string B3DImporter::ReadChunk() {
tag += char(ReadByte()); tag += char(ReadByte());
} }
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_DEBUG("ReadChunk: ", tag); ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
#endif #endif
unsigned sz = (unsigned)ReadInt(); unsigned sz = (unsigned)ReadInt();
_stack.push_back(_pos + sz); _stack.push_back(_pos + sz);
@ -253,7 +255,7 @@ size_t B3DImporter::ChunkSize() {
template <class T> template <class T>
T *B3DImporter::to_array(const vector<T> &v) { T *B3DImporter::to_array(const vector<T> &v) {
if (v.empty()) { if (v.empty()) {
return nullptr; return 0;
} }
T *p = new T[v.size()]; T *p = new T[v.size()];
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
@ -266,7 +268,7 @@ T *B3DImporter::to_array(const vector<T> &v) {
template <class T> template <class T>
T **unique_to_array(vector<std::unique_ptr<T>> &v) { T **unique_to_array(vector<std::unique_ptr<T>> &v) {
if (v.empty()) { if (v.empty()) {
return nullptr; return 0;
} }
T **p = new T *[v.size()]; T **p = new T *[v.size()];
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
@ -329,7 +331,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 +374,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) {
@ -395,7 +397,7 @@ void B3DImporter::ReadTRIS(int v0) {
matid = 0; matid = 0;
} else if (matid < 0 || matid >= (int)_materials.size()) { } else if (matid < 0 || matid >= (int)_materials.size()) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_ERROR("material id=", matid); ASSIMP_LOG_ERROR_F("material id=", matid);
#endif #endif
Fail("Bad material id"); Fail("Bad material id");
} }
@ -415,9 +417,10 @@ void B3DImporter::ReadTRIS(int v0) {
int i2 = ReadInt() + v0; int i2 = ReadInt() + v0;
if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2); ASSIMP_LOG_ERROR_F("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];
@ -476,13 +479,13 @@ void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
while (ChunkSize()) { while (ChunkSize()) {
int frame = ReadInt(); int frame = ReadInt();
if (flags & 1) { if (flags & 1) {
trans.emplace_back(frame, ReadVec3()); trans.push_back(aiVectorKey(frame, ReadVec3()));
} }
if (flags & 2) { if (flags & 2) {
scale.emplace_back(frame, ReadVec3()); scale.push_back(aiVectorKey(frame, ReadVec3()));
} }
if (flags & 4) { if (flags & 4) {
rot.emplace_back(frame, ReadQuat()); rot.push_back(aiQuatKey(frame, ReadQuat()));
} }
} }
@ -616,7 +619,7 @@ void B3DImporter::ReadBB3D(aiScene *scene) {
} else if (chunk == "BRUS") { } else if (chunk == "BRUS") {
ReadBRUS(); ReadBRUS();
} else if (chunk == "NODE") { } else if (chunk == "NODE") {
ReadNODE(nullptr); ReadNODE(0);
} }
ExitChunk(); ExitChunk();
} }
@ -641,7 +644,7 @@ void B3DImporter::ReadBB3D(aiScene *scene) {
int n_tris = mesh->mNumFaces; int n_tris = mesh->mNumFaces;
int n_verts = mesh->mNumVertices = n_tris * 3; int n_verts = mesh->mNumVertices = n_tris * 3;
aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = nullptr, *mc = nullptr; aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = 0, *mc = 0;
if (_vflags & 1) { if (_vflags & 1) {
mn = mesh->mNormals = new aiVector3D[n_verts]; mn = mesh->mNormals = new aiVector3D[n_verts];
} }
@ -670,7 +673,7 @@ void B3DImporter::ReadBB3D(aiScene *scene) {
int bone = v.bones[k]; int bone = v.bones[k];
float weight = v.weights[k]; float weight = v.weights[k];
vweights[bone].emplace_back(vertIdx + faceIndex, weight); vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight));
} }
} }
++face; ++face;
@ -704,22 +707,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();
@ -738,6 +741,4 @@ 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

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -39,10 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** /** @file Definition of the .b3d importer class. */
* @file Definition of the .b3d importer class.
*/
#pragma once
#ifndef AI_B3DIMPORTER_H_INC #ifndef AI_B3DIMPORTER_H_INC
#define AI_B3DIMPORTER_H_INC #define AI_B3DIMPORTER_H_INC
@ -63,12 +62,14 @@ namespace Assimp{
class B3DImporter : public BaseImporter{ class B3DImporter : public BaseImporter{
public: public:
B3DImporter() = default; B3DImporter() = default;
~B3DImporter() override; virtual ~B3DImporter();
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
protected: protected:
const aiImporterDesc* GetInfo () const override;
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override; virtual const aiImporterDesc* GetInfo () const;
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
private: private:
@ -95,7 +96,7 @@ private:
}; };
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void Fail(const std::string &str) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
void ReadTEXS(); void ReadTEXS();
void ReadBRUS(); void ReadBRUS();
@ -112,6 +113,7 @@ private:
void ReadBB3D( aiScene *scene ); void ReadBB3D( aiScene *scene );
size_t _pos; size_t _pos;
// unsigned _size;
std::vector<unsigned char> _buf; std::vector<unsigned char> _buf;
std::vector<size_t> _stack; std::vector<size_t> _stack;

View File

@ -4,7 +4,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
@ -55,11 +55,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map> #include <map>
#include <memory> #include <memory>
namespace Assimp { using namespace Assimp;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
static constexpr aiImporterDesc desc = { static const aiImporterDesc desc = {
"BVH Importer (MoCap)", "BVH Importer (MoCap)",
"", "",
"", "",
@ -72,13 +71,6 @@ static constexpr aiImporterDesc desc = {
"bvh" "bvh"
}; };
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
template <typename... T>
AI_WONT_RETURN void BVHLoader::ThrowException(T &&...args) {
throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BVHLoader::BVHLoader() : BVHLoader::BVHLoader() :
@ -89,13 +81,22 @@ BVHLoader::BVHLoader() :
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
BVHLoader::~BVHLoader() = default; BVHLoader::~BVHLoader() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
static const char *tokens[] = { "HIERARCHY" }; // check file extension
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); const std::string extension = GetExtension(pFile);
if (extension == "bvh")
return true;
if ((!extension.length() || cs) && pIOHandler) {
const char *tokens[] = { "HIERARCHY" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -116,8 +117,8 @@ void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst
// read file into memory // read file into memory
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
if (file == nullptr) { if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open file ", pFile, "."); throw DeadlyImportError("Failed to open file " + pFile + ".");
} }
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
@ -170,29 +171,29 @@ void BVHLoader::ReadHierarchy(aiScene *pScene) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a node and recursively its children and returns the created node; // Reads a node and recursively its childs and returns the created node;
aiNode *BVHLoader::ReadNode() { aiNode *BVHLoader::ReadNode() {
// first token is name // first token is name
std::string nodeName = GetNextToken(); std::string nodeName = GetNextToken();
if (nodeName.empty() || nodeName == "{") if (nodeName.empty() || nodeName == "{")
ThrowException("Expected node name, but found \"", nodeName, "\"."); ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
// then an opening brace should follow // then an opening brace should follow
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
// Create a node // Create a node
aiNode *node = new aiNode(nodeName); aiNode *node = new aiNode(nodeName);
std::vector<aiNode *> childNodes; std::vector<aiNode *> childNodes;
// and create an bone entry for it // and create an bone entry for it
mNodes.emplace_back(node); mNodes.push_back(Node(node));
Node &internNode = mNodes.back(); Node &internNode = mNodes.back();
// now read the node's contents // now read the node's contents
std::string siteToken; std::string siteToken;
while (true) { while (1) {
std::string token = GetNextToken(); std::string token = GetNextToken();
// node offset to parent node // node offset to parent node
@ -210,7 +211,7 @@ aiNode *BVHLoader::ReadNode() {
siteToken.clear(); siteToken.clear();
siteToken = GetNextToken(); siteToken = GetNextToken();
if (siteToken != "Site") if (siteToken != "Site")
ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\"."); ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
aiNode *child = ReadEndSite(nodeName); aiNode *child = ReadEndSite(nodeName);
child->mParent = node; child->mParent = node;
@ -220,7 +221,7 @@ aiNode *BVHLoader::ReadNode() {
break; break;
} else { } else {
// everything else is a parse error // everything else is a parse error
ThrowException("Unknown keyword \"", token, "\"."); ThrowException(format() << "Unknown keyword \"" << token << "\".");
} }
} }
@ -241,14 +242,14 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
// check opening brace // check opening brace
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
// Create a node // Create a node
aiNode *node = new aiNode("EndSite_" + pParentName); aiNode *node = new aiNode("EndSite_" + pParentName);
// now read the node's contents. Only possible entry is "OFFSET" // now read the node's contents. Only possible entry is "OFFSET"
std::string token; std::string token;
while (true) { while (1) {
token.clear(); token.clear();
token = GetNextToken(); token = GetNextToken();
@ -260,7 +261,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
break; break;
} else { } else {
// everything else is a parse error // everything else is a parse error
ThrowException("Unknown keyword \"", token, "\"."); ThrowException(format() << "Unknown keyword \"" << token << "\".");
} }
} }
@ -306,7 +307,7 @@ void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
else if (channelToken == "Zrotation") else if (channelToken == "Zrotation")
pNode.mChannels.push_back(Channel_RotationZ); pNode.mChannels.push_back(Channel_RotationZ);
else else
ThrowException("Invalid channel specifier \"", channelToken, "\"."); ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
} }
} }
@ -316,7 +317,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
// Read number of frames // Read number of frames
std::string tokenFrames = GetNextToken(); std::string tokenFrames = GetNextToken();
if (tokenFrames != "Frames:") if (tokenFrames != "Frames:")
ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\"."); ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
float numFramesFloat = GetNextTokenAsFloat(); float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int)numFramesFloat; mAnimNumFrames = (unsigned int)numFramesFloat;
@ -325,7 +326,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
std::string tokenDuration1 = GetNextToken(); std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken(); std::string tokenDuration2 = GetNextToken();
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\"."); ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
mAnimTickDuration = GetNextTokenAsFloat(); mAnimTickDuration = GetNextTokenAsFloat();
@ -351,7 +352,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
std::string BVHLoader::GetNextToken() { std::string BVHLoader::GetNextToken() {
// skip any preceding whitespace // skip any preceding whitespace
while (mReader != mBuffer.end()) { while (mReader != mBuffer.end()) {
if (!isspace((unsigned char)*mReader)) if (!isspace(*mReader))
break; break;
// count lines // count lines
@ -364,7 +365,7 @@ std::string BVHLoader::GetNextToken() {
// collect all chars till the next whitespace. BVH is easy in respect to that. // collect all chars till the next whitespace. BVH is easy in respect to that.
std::string token; std::string token;
while (mReader != mBuffer.end()) { while (mReader != mBuffer.end()) {
if (isspace((unsigned char)*mReader)) if (isspace(*mReader))
break; break;
token.push_back(*mReader); token.push_back(*mReader);
@ -392,11 +393,17 @@ float BVHLoader::GetNextTokenAsFloat() {
ctoken = fast_atoreal_move<float>(ctoken, result); ctoken = fast_atoreal_move<float>(ctoken, result);
if (ctoken != token.c_str() + token.length()) if (ctoken != token.c_str() + token.length())
ThrowException("Expected a floating point number, but found \"", token, "\"."); ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
return result; return result;
} }
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs an animation for the motion data and stores it in the given scene // Constructs an animation for the motion data and stores it in the given scene
void BVHLoader::CreateAnimation(aiScene *pScene) { void BVHLoader::CreateAnimation(aiScene *pScene) {
@ -427,7 +434,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;
} }
@ -442,11 +449,11 @@ 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())
throw DeadlyImportError("Missing position channel in node ", nodeName); throw DeadlyImportError("Missing position channel in node " + nodeName);
else { else {
int channelIdx = mapIter->second; int channelIdx = mapIter->second;
switch (channel) { switch (channel) {
@ -486,23 +493,26 @@ 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); aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( 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); aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( 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); aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
rotMatrix *= aiMatrix3x3(temp); }
} break; break;
default: default:
break; break;
} }
@ -523,6 +533,4 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
} }
} }
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER

View File

@ -4,7 +4,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -112,7 +112,7 @@ protected:
/** Reads the hierarchy */ /** Reads the hierarchy */
void ReadHierarchy(aiScene *pScene); void ReadHierarchy(aiScene *pScene);
/** Reads a node and recursively its children and returns the created node. */ /** Reads a node and recursively its childs and returns the created node. */
aiNode *ReadNode(); aiNode *ReadNode();
/** Reads an end node and returns the created node. */ /** Reads an end node and returns the created node. */
@ -134,8 +134,7 @@ protected:
float GetNextTokenAsFloat(); float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
template<typename... T> AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX;
/** Constructs an animation for the motion data and stores it in the given scene */ /** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation(aiScene *pScene); void CreateAnimation(aiScene *pScene);

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, 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,
@ -52,7 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
template <> template <>
const char *LogFunctions<BlenderBMeshConverter>::Prefix() { const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
return "BLEND_BMESH: "; static auto prefix = "BLEND_BMESH: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp
@ -139,7 +140,7 @@ void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
ThrowException("BMesh uv loop array has incorrect size"); ThrowException("BMesh uv loop array has incorrect size");
} }
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart]; const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : nullptr); AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0);
} }
} else if (poly.totloop > 4) { } else if (poly.totloop > 4) {
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE #if ASSIMP_BLEND_WITH_GLU_TESSELLATE

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, 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,
@ -80,7 +80,7 @@ namespace Assimp
void DestroyTriMesh( ); void DestroyTriMesh( );
void ConvertPolyToFaces( const Blender::MPoly& poly ); void ConvertPolyToFaces( const Blender::MPoly& poly );
void AddFace( int v1, int v2, int v3, int v4 = 0 ); void AddFace( int v1, int v2, int v3, int v4 = 0 );
void AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4 = nullptr); void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
const Blender::Mesh* BMesh; const Blender::Mesh* BMesh;
Blender::Mesh* triMesh; Blender::Mesh* triMesh;

View File

@ -96,8 +96,7 @@ 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
*/ */
static std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge), DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
@ -150,7 +149,7 @@ bool isValidCustomDataType(const int cdtype) {
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) { bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) { if (!isValidCustomDataType(cdtype)) {
throw Error("CustomData.type ", cdtype, " out of index"); throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
} }
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -72,7 +72,7 @@ struct Type {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DNAParser::Parse() { void DNAParser::Parse() {
StreamReaderAny &stream = *db.reader; StreamReaderAny &stream = *db.reader.get();
DNA &dna = db.dna; DNA &dna = db.dna;
if (!match4(stream, "SDNA")) { if (!match4(stream, "SDNA")) {
@ -130,7 +130,9 @@ void DNAParser::Parse() {
uint16_t n = stream.GetI2(); uint16_t n = stream.GetI2();
if (n >= types.size()) { if (n >= types.size()) {
throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)"); throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure name", n,
" (there are only ", types.size(), " entries)"));
} }
// maintain separate indexes // maintain separate indexes
@ -139,6 +141,7 @@ void DNAParser::Parse() {
dna.structures.push_back(Structure()); dna.structures.push_back(Structure());
Structure &s = dna.structures.back(); Structure &s = dna.structures.back();
s.name = types[n].name; s.name = types[n].name;
//s.index = dna.structures.size()-1;
n = stream.GetI2(); n = stream.GetI2();
s.fields.reserve(n); s.fields.reserve(n);
@ -148,7 +151,9 @@ void DNAParser::Parse() {
uint16_t j = stream.GetI2(); uint16_t j = stream.GetI2();
if (j >= types.size()) { if (j >= types.size()) {
throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)"); throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"));
} }
s.fields.push_back(Field()); s.fields.push_back(Field());
Field &f = s.fields.back(); Field &f = s.fields.back();
@ -159,7 +164,9 @@ void DNAParser::Parse() {
j = stream.GetI2(); j = stream.GetI2();
if (j >= names.size()) { if (j >= names.size()) {
throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)"); throw DeadlyImportError((format(),
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"));
} }
f.name = names[j]; f.name = names[j];
@ -181,7 +188,9 @@ void DNAParser::Parse() {
if (*f.name.rbegin() == ']') { if (*f.name.rbegin() == ']') {
const std::string::size_type rb = f.name.find('['); const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) { if (rb == std::string::npos) {
throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name); throw DeadlyImportError((format(),
"BlenderDNA: Encountered invalid array declaration ",
f.name));
} }
f.flags |= FieldFlag_Array; f.flags |= FieldFlag_Array;
@ -198,9 +207,9 @@ void DNAParser::Parse() {
s.size = offset; s.size = offset;
} }
ASSIMP_LOG_DEBUG("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields"); ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
#if ASSIMP_BUILD_BLENDER_DEBUG_DNA #ifdef ASSIMP_BUILD_BLENDER_DEBUG
dna.DumpToFile(); dna.DumpToFile();
#endif #endif
@ -208,7 +217,7 @@ void DNAParser::Parse() {
dna.RegisterConverters(); dna.RegisterConverters();
} }
#if ASSIMP_BUILD_BLENDER_DEBUG_DNA #ifdef ASSIMP_BUILD_BLENDER_DEBUG
#include <fstream> #include <fstream>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -237,7 +246,7 @@ void DNA ::DumpToFile() {
ASSIMP_LOG_INFO("BlenderDNA: Dumped dna to dna.txt"); ASSIMP_LOG_INFO("BlenderDNA: Dumped dna to dna.txt");
} }
#endif // ASSIMP_BUILD_BLENDER_DEBUG_DNA #endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/*static*/ void DNA ::ExtractArraySize( /*static*/ void DNA ::ExtractArraySize(
@ -325,10 +334,10 @@ void SectionParser ::Next() {
stream.SetCurrentPos(current.start + current.size); stream.SetCurrentPos(current.start + current.size);
const char tmp[] = { const char tmp[] = {
(char)stream.GetI1(), (const char)stream.GetI1(),
(char)stream.GetI1(), (const char)stream.GetI1(),
(char)stream.GetI1(), (const char)stream.GetI1(),
(char)stream.GetI1() (const char)stream.GetI1()
}; };
current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1); current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -59,13 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define ASSIMP_BUILD_BLENDER_DEBUG #define ASSIMP_BUILD_BLENDER_DEBUG
#endif #endif
// set this to non-zero to dump BlenderDNA stuff to dna.txt.
// you could set it on the assimp build command line too without touching it here.
// !!! please make sure this is set to 0 in the repo !!!
#ifndef ASSIMP_BUILD_BLENDER_DEBUG_DNA
#define ASSIMP_BUILD_BLENDER_DEBUG_DNA 0
#endif
// #define ASSIMP_BUILD_BLENDER_NO_STATS // #define ASSIMP_BUILD_BLENDER_NO_STATS
namespace Assimp { namespace Assimp {
@ -90,9 +83,9 @@ class ObjectCache;
* ancestry. */ * ancestry. */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct Error : DeadlyImportError { struct Error : DeadlyImportError {
template <typename... T> Error(const std::string &s) :
explicit Error(T &&...args) : DeadlyImportError(s) {
DeadlyImportError(args...) { // empty
} }
}; };
@ -106,7 +99,9 @@ struct ElemBase {
// empty // empty
} }
virtual ~ElemBase() = default; virtual ~ElemBase() {
// empty
}
/** Type name of the element. The type /** Type name of the element. The type
* string points is the `c_str` of the `name` attribute of the * string points is the `c_str` of the `name` attribute of the
@ -191,7 +186,7 @@ struct Field {
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** Range of possible behaviors for fields absence in the input file. Some are /** Range of possible behaviours for fields absend in the input file. Some are
* mission critical so we need them, while others can silently be default * mission critical so we need them, while others can silently be default
* initialized and no animations are harmed. */ * initialized and no animations are harmed. */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -399,7 +394,7 @@ private:
// -------------------------------------------------------- // --------------------------------------------------------
template <> template <>
struct Structure::_defaultInitializer<ErrorPolicy_Warn> { struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
template <typename T> template <typename T>
void operator()(T &out, const char *reason = "<add reason>") { void operator()(T &out, const char *reason = "<add reason>") {
@ -411,13 +406,13 @@ struct Structure::_defaultInitializer<ErrorPolicy_Warn> {
}; };
template <> template <>
struct Structure::_defaultInitializer<ErrorPolicy_Fail> { struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
template <typename T> template <typename T>
void operator()(T & /*out*/, const char *message = "") { void operator()(T & /*out*/, const char * = "") {
// obviously, it is crucial that _DefaultInitializer is used // obviously, it is crucial that _DefaultInitializer is used
// only from within a catch clause. // only from within a catch clause.
throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error: ", message); throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
} }
}; };
@ -429,17 +424,6 @@ inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_pt
const Field &f, const Field &f,
bool) const; bool) const;
template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(
std::shared_ptr<ElemBase>& out, const Pointer & ptrval,
const FileDatabase& db, const Field&, bool) const;
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
template<> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
template <> inline void Structure::Convert<unsigned char>(unsigned char& dest, const FileDatabase& db) const;
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** Represents the full data structure information for a single BLEND file. /** Represents the full data structure information for a single BLEND file.
* This data is extracted from the DNA1 chunk in the file. * This data is extracted from the DNA1 chunk in the file.
@ -485,7 +469,7 @@ public:
* in BlenderScene.cpp and is machine-generated. * in BlenderScene.cpp and is machine-generated.
* Converters are used to quickly handle objects whose * Converters are used to quickly handle objects whose
* exact data type is a runtime-property and not yet * exact data type is a runtime-property and not yet
* known at compile time (consider Object::data).*/ * known at compile time (consier Object::data).*/
void RegisterConverters(); void RegisterConverters();
// -------------------------------------------------------- // --------------------------------------------------------
@ -511,7 +495,7 @@ public:
const Structure &structure, const Structure &structure,
const FileDatabase &db) const; const FileDatabase &db) const;
#if ASSIMP_BUILD_BLENDER_DEBUG_DNA #ifdef ASSIMP_BUILD_BLENDER_DEBUG
// -------------------------------------------------------- // --------------------------------------------------------
/** Dump the DNA to a text file. This is for debugging purposes. /** Dump the DNA to a text file. This is for debugging purposes.
* The output file is `dna.txt` in the current working folder*/ * The output file is `dna.txt` in the current working folder*/

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -57,7 +57,9 @@ const Field& Structure :: operator [] (const std::string& ss) const
{ {
std::map<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"); throw Error((Formatter::format(),
"BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
));
} }
return fields[(*it).second]; return fields[(*it).second];
@ -74,7 +76,9 @@ const Field* Structure :: Get (const std::string& ss) const
const Field& Structure :: operator [] (const size_t i) const const Field& Structure :: operator [] (const size_t i) const
{ {
if (i >= fields.size()) { if (i >= fields.size()) {
throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`"); throw Error((Formatter::format(),
"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
));
} }
return fields[i]; return fields[i];
@ -105,7 +109,9 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab
// is the input actually an array? // is the input actually an array?
if (!(f.flags & FieldFlag_Array)) { if (!(f.flags & FieldFlag_Array)) {
throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M); throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M
));
} }
db.reader->IncPtr(f.offset); db.reader->IncPtr(f.offset);
@ -142,9 +148,9 @@ void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileD
// is the input actually an array? // is the input actually an array?
if (!(f.flags & FieldFlag_Array)) { if (!(f.flags & FieldFlag_Array)) {
throw Error("Field `",name,"` of structure `", throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M,"*",N this->name,"` ought to be an array of size ",M,"*",N
); ));
} }
db.reader->IncPtr(f.offset); db.reader->IncPtr(f.offset);
@ -189,8 +195,8 @@ bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabas
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error("Field `",name,"` of structure `", throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer"); this->name,"` ought to be a pointer"));
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -235,8 +241,8 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
#ifdef _DEBUG #ifdef _DEBUG
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error("Field `",name,"` of structure `", throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array"); this->name,"` ought to be a pointer AND an array"));
} }
#endif // _DEBUG #endif // _DEBUG
@ -316,8 +322,8 @@ bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, con
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error("Field `", name, "` of structure `", throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"); this->name, "` ought to be a pointer"));
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -363,8 +369,8 @@ bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error("Field `", name, "` of structure `", throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"); this->name, "` ought to be a pointer"));
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -422,9 +428,9 @@ bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const Fil
// and check if it matches the type which we expect. // and check if it matches the type which we expect.
const Structure& ss = db.dna[block->dna_index]; const Structure& ss = db.dna[block->dna_index];
if (ss != s) { if (ss != s) {
throw Error("Expected target to be of type `",s.name, throw Error((Formatter::format(),"Expected target to be of type `",s.name,
"` but seemingly it is a `",ss.name,"` instead" "` but seemingly it is a `",ss.name,"` instead"
); ));
} }
// try to retrieve the object from the cache // try to retrieve the object from the cache
@ -565,7 +571,7 @@ template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shar
// this might happen if DNA::RegisterConverters hasn't been called so far // this might happen if DNA::RegisterConverters hasn't been called so far
// or if the target type is not contained in `our` DNA. // or if the target type is not contained in `our` DNA.
out.reset(); out.reset();
ASSIMP_LOG_WARN( "Failed to find a converter for the `",s.name,"` structure" ); ASSIMP_LOG_WARN_F( "Failed to find a converter for the `",s.name,"` structure" );
return false; return false;
} }
@ -608,14 +614,16 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
if (it == db.entries.end()) { if (it == db.entries.end()) {
// this is crucial, pointers may not be invalid. // this is crucial, pointers may not be invalid.
// this is either a corrupted file or an attempted attack. // this is either a corrupted file or an attempted attack.
throw DeadlyImportError("Failure resolving pointer 0x", throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range"); std::hex,ptrval.val,", no file block falls into this address range"
));
} }
if (ptrval.val >= (*it).address.val + (*it).size) { if (ptrval.val >= (*it).address.val + (*it).size) {
throw DeadlyImportError("Failure resolving pointer 0x", throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
std::hex,ptrval.val,", nearest file block starting at 0x", std::hex,ptrval.val,", nearest file block starting at 0x",
(*it).address.val," ends at 0x", (*it).address.val," ends at 0x",
(*it).address.val + (*it).size); (*it).address.val + (*it).size
));
} }
return &*it; return &*it;
} }
@ -668,7 +676,7 @@ template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,
out = static_cast<T>(db.reader->GetF8()); out = static_cast<T>(db.reader->GetF8());
} }
else { else {
throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name); throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name);
} }
} }
@ -776,7 +784,9 @@ const Structure& DNA :: operator [] (const std::string& ss) const
{ {
std::map<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error("BlendDNA: Did not find a structure named `",ss,"`"); throw Error((Formatter::format(),
"BlendDNA: Did not find a structure named `",ss,"`"
));
} }
return structures[(*it).second]; return structures[(*it).second];
@ -793,7 +803,9 @@ const Structure* DNA :: Get (const std::string& ss) const
const Structure& DNA :: operator [] (const size_t i) const const Structure& DNA :: operator [] (const size_t i) const
{ {
if (i >= structures.size()) { if (i >= structures.size()) {
throw Error("BlendDNA: There is no structure with index `",i,"`"); throw Error((Formatter::format(),
"BlendDNA: There is no structure with index `",i,"`"
));
} }
return structures[i]; return structures[i];

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -65,7 +65,8 @@ namespace Blender {
struct TempArray { struct TempArray {
typedef TCLASS< T*,std::allocator<T*> > mywrap; typedef TCLASS< T*,std::allocator<T*> > mywrap;
TempArray() = default; TempArray() {
}
~TempArray () { ~TempArray () {
for(T* elem : arr) { for(T* elem : arr) {

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -63,29 +63,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <cctype> #include <cctype>
#include <memory>
#include <utility>
// 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" #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif
#endif #endif
namespace Assimp { namespace Assimp {
template <> template <>
const char *LogFunctions<BlenderImporter>::Prefix() { const char *LogFunctions<BlenderImporter>::Prefix() {
return "BLEND: "; static auto prefix = "BLEND: ";
return prefix;
} }
} // namespace Assimp } // namespace Assimp
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Blender; using namespace Assimp::Blender;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
static constexpr aiImporterDesc blenderDesc = { static const aiImporterDesc blenderDesc = {
"Blender 3D Importer (http://www.blender3d.org)", "Blender 3D Importer \nhttp://www.blender3d.org",
"", "",
"", "",
"No animation support yet", "No animation support yet",
@ -110,12 +111,28 @@ BlenderImporter::~BlenderImporter() {
delete modifier_cache; delete modifier_cache;
} }
static const char Token[] = "BLENDER"; static const char *Tokens[] = { "BLENDER" };
static const char *TokensForSearch[] = { "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 {
return ParseMagicToken(pFile, pIOHandler).error.empty(); const std::string &extension = GetExtension(pFile);
if (extension == "blend") {
return true;
}
else if ((!extension.length() || checkSig) && pIOHandler) {
// note: this won't catch compressed files
return SearchFileHeaderForToken(pIOHandler, pFile, TokensForSearch, 1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
// List all extensions handled by this loader
void BlenderImporter::GetExtensionList(std::set<std::string> &app) {
app.insert("blend");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -134,25 +151,98 @@ 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<Bytef> uncompressed;
#endif
FileDatabase file; FileDatabase file;
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler); std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (!streamOrError.error.empty()) { if (!stream) {
ThrowException(streamOrError.error); ThrowException("Could not open file for reading");
} }
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
char version[4] = { 0 }; char magic[8] = { 0 };
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-'); stream->Read(magic, 7, 1);
file.little = (stream->Read(version, 1, 1), version[0] == 'v'); if (strcmp(magic, Tokens[0])) {
// Check for presence of the gzip header. If yes, assume it is a
// compressed blend file and try uncompressing it, else fail. This is to
// avoid uncompressing random files which our loader might end up with.
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
#else
stream->Read(version, 3, 1); if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
version[3] = '\0'; ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
}
LogInfo("Blender version is ", version[0], ".", version + 1, LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
if (magic[2] != 8) {
ThrowException("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));
// build a zlib stream
z_stream zstream;
zstream.opaque = Z_NULL;
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zstream.data_type = Z_BINARY;
// http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
inflateInit2(&zstream, 16 + MAX_WBITS);
zstream.next_in = reinterpret_cast<Bytef *>(reader->GetPtr());
zstream.avail_in = (uInt)reader->GetRemainingSize();
size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024
Bytef block[MYBLOCK];
int ret;
do {
zstream.avail_out = MYBLOCK;
zstream.next_out = block;
ret = inflate(&zstream, Z_NO_FLUSH);
if (ret != Z_STREAM_END && ret != Z_OK) {
ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
}
const size_t have = MYBLOCK - zstream.avail_out;
total += have;
uncompressed.resize(total);
memcpy(uncompressed.data() + total - have, block, have);
} while (ret != Z_STREAM_END);
// terminate zlib
inflateEnd(&zstream);
// replace the input stream with a memory stream
stream.reset(new 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((format(), "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", ")"));
ParseBlendFile(file, std::move(stream)); ParseBlendFile(file, stream);
Scene scene; Scene scene;
ExtractScene(scene, file); ExtractScene(scene, file);
@ -162,14 +252,14 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderImporter::ParseBlendFile(FileDatabase &out, std::shared_ptr<IOStream> stream) { void BlenderImporter::ParseBlendFile(FileDatabase &out, std::shared_ptr<IOStream> stream) {
out.reader = std::make_shared<StreamReaderAny>(stream, out.little); out.reader = std::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream, out.little));
DNAParser dna_reader(out); DNAParser dna_reader(out);
const DNA *dna = nullptr; const DNA *dna = nullptr;
out.entries.reserve(128); out.entries.reserve(128);
{ // even small BLEND files tend to consist of many file blocks { // even small BLEND files tend to consist of many file blocks
SectionParser parser(*out.reader, out.i64bit); SectionParser parser(*out.reader.get(), out.i64bit);
// first parse the file in search for the DNA and insert all other sections into the database // first parse the file in search for the DNA and insert all other sections into the database
while ((parser.Next(), 1)) { while ((parser.Next(), 1)) {
@ -223,7 +313,7 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
ss.Convert(out, file); ss.Convert(out, file);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
ASSIMP_LOG_INFO( ASSIMP_LOG_INFO_F(
"(Stats) Fields read: ", file.stats().fields_read, "(Stats) Fields read: ", file.stats().fields_read,
", pointers resolved: ", file.stats().pointers_resolved, ", pointers resolved: ", file.stats().pointers_resolved,
", cache hits: ", file.stats().cache_hits, ", cache hits: ", file.stats().cache_hits,
@ -231,53 +321,13 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
#endif #endif
} }
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, const std::shared_ptr<Collection>& collection, ConversionData &conv_data) {
std::deque<Object *> root_objects;
// Count number of objects
for (std::shared_ptr<CollectionObject> cur = std::static_pointer_cast<CollectionObject>(collection->gobject.first); cur; cur = cur->next) {
if (cur->ob) {
root_objects.push_back(cur->ob);
}
}
std::deque<Collection *> root_children;
// Count number of child nodes
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root_children.push_back(cur->collection.get());
}
}
root->mNumChildren = static_cast<unsigned int>(root_objects.size() + root_children.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < static_cast<unsigned int>(root_objects.size()); ++i) {
root->mChildren[i] = ConvertNode(in, root_objects[i], conv_data, aiMatrix4x4());
root->mChildren[i]->mParent = root;
}
// For each subcollection create a new node to represent it
unsigned int iterator = static_cast<unsigned int>(root_objects.size());
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root->mChildren[iterator] = new aiNode(cur->collection->id.name + 2); // skip over the name prefix 'OB'
root->mChildren[iterator]->mParent = root;
ParseSubCollection(in, root->mChildren[iterator], cur->collection, conv_data);
}
iterator += 1;
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) { void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
ConversionData conv(file); ConversionData conv(file);
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>"); // FIXME it must be possible to take the hierarchy directly from
// Iterate over all objects directly under master_collection, // the file. This is terrible. Here, we're first looking for
// If in.master_collection == null, then we're parsing something older. // all objects which don't have parent objects at all -
if (in.master_collection) {
ParseSubCollection(in, root, in.master_collection, conv);
} else {
std::deque<const Object *> no_parents; std::deque<const Object *> no_parents;
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) { for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
if (cur->object) { if (cur->object) {
@ -300,13 +350,14 @@ void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const File
ThrowException("Expected at least one object with no parent"); ThrowException("Expected at least one object with no parent");
} }
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
root->mNumChildren = static_cast<unsigned int>(no_parents.size()); root->mNumChildren = static_cast<unsigned int>(no_parents.size());
root->mChildren = new aiNode *[root->mNumChildren](); root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < root->mNumChildren; ++i) { for (unsigned int i = 0; i < root->mNumChildren; ++i) {
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4()); root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
root->mChildren[i]->mParent = root; root->mChildren[i]->mParent = root;
} }
}
BuildMaterials(conv); BuildMaterials(conv);
@ -359,7 +410,7 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
// check if the file contents are bundled with the BLEND file // check if the file contents are bundled with the BLEND file
if (img->packedfile) { if (img->packedfile) {
name.data[0] = '*'; name.data[0] = '*';
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(AI_MAXLEN - 1), static_cast<int32_t>(conv_data.textures->size())); name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(conv_data.textures->size()));
conv_data.textures->push_back(new aiTexture()); conv_data.textures->push_back(new aiTexture());
aiTexture *curTex = conv_data.textures->back(); aiTexture *curTex = conv_data.textures->back();
@ -372,9 +423,9 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
--s; --s;
} }
curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower((unsigned char)s[1]); curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower((unsigned char)s[2]); curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower((unsigned char)s[3]); curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
curTex->achFormatHint[3] = '\0'; curTex->achFormatHint[3] = '\0';
// tex->mHeight = 0; // tex->mHeight = 0;
@ -386,7 +437,7 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
curTex->pcData = reinterpret_cast<aiTexel *>(ch); curTex->pcData = reinterpret_cast<aiTexel *>(ch);
LogInfo("Reading embedded texture, original file was ", img->name); LogInfo("Reading embedded texture, original file was " + std::string(img->name));
} else { } else {
name = aiString(img->name); name = aiString(img->name);
} }
@ -433,7 +484,7 @@ void BlenderImporter::AddSentinelTexture(aiMaterial *out, const Material *mat, c
(void)conv_data; (void)conv_data;
aiString name; aiString name;
name.length = ai_snprintf(name.data, AI_MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++, name.length = ai_snprintf(name.data, MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
GetTextureTypeDisplayString(tex->tex->type)); GetTextureTypeDisplayString(tex->tex->type));
out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE( out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(
conv_data.next_texture[aiTextureType_DIFFUSE]++)); conv_data.next_texture[aiTextureType_DIFFUSE]++));
@ -468,7 +519,7 @@ void BlenderImporter::ResolveTexture(aiMaterial *out, const Material *mat, const
case Tex::Type_POINTDENSITY: case Tex::Type_POINTDENSITY:
case Tex::Type_VOXELDATA: case Tex::Type_VOXELDATA:
LogWarn("Encountered a texture with an unsupported type: ", dispnam); LogWarn(std::string("Encountered a texture with an unsupported type: ") + dispnam);
AddSentinelTexture(out, mat, tex, conv_data); AddSentinelTexture(out, mat, tex, conv_data);
break; break;
@ -631,7 +682,7 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
BuildDefaultMaterial(conv_data); BuildDefaultMaterial(conv_data);
for (const std::shared_ptr<Material> &mat : conv_data.materials_raw) { for (std::shared_ptr<Material> mat : conv_data.materials_raw) {
// reset per material global counters // reset per material global counters
for (size_t i = 0; i < sizeof(conv_data.next_texture) / sizeof(conv_data.next_texture[0]); ++i) { for (size_t i = 0; i < sizeof(conv_data.next_texture) / sizeof(conv_data.next_texture[0]); ++i) {
@ -697,14 +748,15 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) { void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
ai_assert(dt); ai_assert(dt);
if (strcmp(dt->dna_type, check)) { if (strcmp(dt->dna_type, check)) {
ThrowException("Expected object at ", std::hex, dt, " to be of type `", check, ThrowException((format(),
"`, but it claims to be a `", dt->dna_type, "`instead"); "Expected object at ", std::hex, dt, " to be of type `", check,
"`, but it claims to be a `", dt->dna_type, "`instead"));
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderImporter::NotSupportedObjectType(const Object *obj, const char *type) { void BlenderImporter::NotSupportedObjectType(const Object *obj, const char *type) {
LogWarn("Object `", obj->id.name, "` - type is unsupported: `", type, "`, skipping"); LogWarn((format(), "Object `", obj->id.name, "` - type is unsupported: `", type, "`, skipping"));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -937,7 +989,7 @@ void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/,
// key is material number, value is the TextureUVMapping for the material // key is material number, value is the TextureUVMapping for the material
typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings; typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
MaterialTextureUVMappings matTexUvMappings; MaterialTextureUVMappings matTexUvMappings;
const uint32_t maxMat = static_cast<uint32_t>(mesh->mat.size()); const uint32_t maxMat = static_cast<const uint32_t>(mesh->mat.size());
for (uint32_t m = 0; m < maxMat; ++m) { for (uint32_t m = 0; m < maxMat; ++m) {
// get material by index // get material by index
const std::shared_ptr<Material> pMat = mesh->mat[m]; const std::shared_ptr<Material> pMat = mesh->mat[m];
@ -1288,55 +1340,4 @@ 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

@ -2,7 +2,8 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -42,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file BlenderLoader.h /** @file BlenderLoader.h
* @brief Declaration of the Blender 3D (*.blend) importer class. * @brief Declaration of the Blender 3D (*.blend) importer class.
*/ */
#pragma once
#ifndef INCLUDED_AI_BLEND_LOADER_H #ifndef INCLUDED_AI_BLEND_LOADER_H
#define INCLUDED_AI_BLEND_LOADER_H #define INCLUDED_AI_BLEND_LOADER_H
@ -58,152 +58,181 @@ struct aiMaterial;
namespace Assimp { namespace Assimp {
// TinyFormatter.h // TinyFormatter.h
namespace Formatter { namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
template <typename T, typename TR, typename A> // BlenderDNA.h
class basic_formatter; namespace Blender {
class FileDatabase;
struct ElemBase;
}
typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>> format; // BlenderScene.h
namespace Blender {
struct Scene;
struct Object;
struct Mesh;
struct Camera;
struct Lamp;
struct MTex;
struct Image;
struct Material;
}
} // namespace Formatter // BlenderIntermediate.h
namespace Blender {
struct ConversionData;
template <template <typename,typename> class TCLASS, typename T> struct TempArray;
}
// BlenderDNA.h // BlenderModifier.h
namespace Blender { namespace Blender {
class FileDatabase; class BlenderModifierShowcase;
struct ElemBase; class BlenderModifier;
} // namespace Blender }
// BlenderScene.h
namespace Blender {
struct Scene;
struct Object;
struct Collection;
struct Mesh;
struct Camera;
struct Lamp;
struct MTex;
struct Image;
struct Material;
} // namespace Blender
// BlenderIntermediate.h
namespace Blender {
struct ConversionData;
template <template <typename, typename> class TCLASS, typename T>
struct TempArray;
} // namespace Blender
// BlenderModifier.h
namespace Blender {
class BlenderModifierShowcase;
class BlenderModifier;
} // namespace Blender
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
/** Load blenders official binary format. The actual file structure (the `DNA` how they /** Load blenders official binary format. The actual file structure (the `DNA` how they
* call it is outsourced to BlenderDNA.cpp/BlenderDNA.h. This class only performs the * call it is outsourced to BlenderDNA.cpp/BlenderDNA.h. This class only performs the
* conversion from intermediate format to aiScene. */ * conversion from intermediate format to aiScene. */
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter> { class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter>
{
public: public:
BlenderImporter(); BlenderImporter();
~BlenderImporter() override; ~BlenderImporter();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
public:
// --------------------
bool CanRead( const std::string& pFile,
IOSystem* pIOHandler,
bool checkSig
) const;
protected: protected:
const aiImporterDesc *GetInfo() const override;
void SetupProperties(const Importer *pImp) override; // --------------------
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override; const aiImporterDesc* GetInfo () const;
void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file); // --------------------
void ParseSubCollection(const Blender::Scene &in, aiNode *root, const std::shared_ptr<Blender::Collection>& collection, Blender::ConversionData &conv_data); void GetExtensionList(std::set<std::string>& app);
void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
);
// --------------------
void ParseBlendFile(Blender::FileDatabase& out,
std::shared_ptr<IOStream> stream
);
// --------------------
void ExtractScene(Blender::Scene& out,
const Blender::FileDatabase& file
);
// --------------------
void ConvertBlendFile(aiScene* out,
const Blender::Scene& in,
const Blender::FileDatabase& file
);
private: private:
aiNode *ConvertNode(const Blender::Scene &in,
const Blender::Object *obj,
Blender::ConversionData &conv_info,
const aiMatrix4x4 &parentTransform);
// -------------------- // --------------------
void ConvertMesh(const Blender::Scene &in, aiNode* ConvertNode(const Blender::Scene& in,
const Blender::Object *obj, const Blender::Object* obj,
const Blender::Mesh *mesh, Blender::ConversionData& conv_info,
Blender::ConversionData &conv_data, const aiMatrix4x4& parentTransform
Blender::TempArray<std::vector, aiMesh> &temp); );
// -------------------- // --------------------
aiLight *ConvertLight(const Blender::Scene &in, void ConvertMesh(const Blender::Scene& in,
const Blender::Object *obj, const Blender::Object* obj,
const Blender::Lamp *mesh, const Blender::Mesh* mesh,
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data,
Blender::TempArray<std::vector,aiMesh>& temp
);
// -------------------- // --------------------
aiCamera *ConvertCamera(const Blender::Scene &in, aiLight* ConvertLight(const Blender::Scene& in,
const Blender::Object *obj, const Blender::Object* obj,
const Blender::Camera *mesh, const Blender::Lamp* mesh,
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data
);
// --------------------
aiCamera* ConvertCamera(const Blender::Scene& in,
const Blender::Object* obj,
const Blender::Camera* mesh,
Blender::ConversionData& conv_data
);
// -------------------- // --------------------
void BuildDefaultMaterial( void BuildDefaultMaterial(
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data
);
// --------------------
void AddBlendParams( void AddBlendParams(
aiMaterial *result, aiMaterial* result,
const Blender::Material *source); const Blender::Material* source
);
// --------------------
void BuildMaterials( void BuildMaterials(
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data
);
// -------------------- // --------------------
void ResolveTexture( void ResolveTexture(
aiMaterial *out, aiMaterial* out,
const Blender::Material *mat, const Blender::Material* mat,
const Blender::MTex *tex, const Blender::MTex* tex,
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data
);
// -------------------- // --------------------
void ResolveImage( void ResolveImage(
aiMaterial *out, aiMaterial* out,
const Blender::Material *mat, const Blender::Material* mat,
const Blender::MTex *tex, const Blender::MTex* tex,
const Blender::Image *img, const Blender::Image* img,
Blender::ConversionData &conv_data); Blender::ConversionData& conv_data
);
// --------------------
void AddSentinelTexture( void AddSentinelTexture(
aiMaterial *out, aiMaterial* out,
const Blender::Material *mat, const Blender::Material* mat,
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,
const char *check);
// -------------------- // --------------------
static void NotSupportedObjectType(const Blender::Object *obj, static void CheckActualType(const Blender::ElemBase* dt,
const char *type); const char* check
);
// --------------------
static void NotSupportedObjectType(const Blender::Object* obj,
const char* type
);
private: private:
Blender::BlenderModifierShowcase *modifier_cache;
Blender::BlenderModifierShowcase* modifier_cache;
}; // !class BlenderImporter }; // !class BlenderImporter

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -71,6 +71,10 @@ static const fpCreateModifier creators[] = {
nullptr // sentinel nullptr // sentinel
}; };
// ------------------------------------------------------------------------------------------------
struct SharedModifierData : ElemBase {
ModifierData modifier;
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) { void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) {
@ -86,7 +90,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
const Structure *s = conv_data.db.dna.Get(cur->dna_type); const Structure *s = conv_data.db.dna.Get(cur->dna_type);
if (!s) { if (!s) {
ASSIMP_LOG_WARN("BlendModifier: could not resolve DNA name: ", cur->dna_type); ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ", cur->dna_type);
continue; continue;
} }
@ -128,7 +132,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
} }
} }
if (curgod) { if (curgod) {
ASSIMP_LOG_WARN("Couldn't find a handler for modifier: ", dat.name); ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ", dat.name);
} }
} }
@ -136,7 +140,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
// object, we still can't say whether our modifier implementations were // object, we still can't say whether our modifier implementations were
// able to fully do their job. // able to fully do their job.
if (ful) { if (ful) {
ASSIMP_LOG_DEBUG("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name, ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name,
"`, check log messages above for errors"); "`, check log messages above for errors");
} }
} }
@ -153,7 +157,6 @@ void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers() // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier); const MirrorModifierData &mir = static_cast<const MirrorModifierData &>(orig_modifier);
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror); ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
std::shared_ptr<Object> mirror_ob = mir.mirror_ob.lock();
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes); conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
@ -168,8 +171,8 @@ void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f; const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f; const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
if (mirror_ob) { if (mir.mirror_ob) {
const aiVector3D center(mirror_ob->obmat[3][0], mirror_ob->obmat[3][1], mirror_ob->obmat[3][2]); const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]);
for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
aiVector3D &v = mesh->mVertices[j]; aiVector3D &v = mesh->mVertices[j];
@ -245,7 +248,7 @@ void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const
out.mMeshes = nind; out.mMeshes = nind;
out.mNumMeshes *= 2; out.mNumMeshes *= 2;
ASSIMP_LOG_INFO("BlendModifier: Applied the `Mirror` modifier to `", ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
orig_object.id.name, "`"); orig_object.id.name, "`");
} }
@ -274,7 +277,7 @@ void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data,
break; break;
default: default:
ASSIMP_LOG_WARN("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType); ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
return; return;
}; };
@ -283,18 +286,13 @@ 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]());
subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true); subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true);
std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes); std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes);
ASSIMP_LOG_INFO("BlendModifier: Applied the `Subdivision` modifier to `", ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
orig_object.id.name, "`"); orig_object.id.name, "`");
} }

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
Copyright (c) 2006-2024, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
@ -62,7 +62,9 @@ public:
/** /**
* The class destructor, virtual. * The class destructor, virtual.
*/ */
virtual ~BlenderModifier() = default; virtual ~BlenderModifier() {
// empty
}
// -------------------- // --------------------
/** /**
@ -84,7 +86,7 @@ public:
const Scene& /*in*/, const Scene& /*in*/,
const Object& /*orig_object*/ const Object& /*orig_object*/
) { ) {
ASSIMP_LOG_INFO("This modifier is not supported, skipping: ",orig_modifier.dna_type ); ASSIMP_LOG_INFO_F("This modifier is not supported, skipping: ",orig_modifier.dna_type );
return; return;
} }
}; };

View File

@ -49,8 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BlenderDNA.h" #include "BlenderDNA.h"
#include "BlenderSceneGen.h" #include "BlenderSceneGen.h"
namespace Assimp { using namespace Assimp;
namespace Blender { using namespace Assimp::Blender;
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
template <> template <>
@ -94,48 +94,6 @@ void Structure ::Convert<Group>(
db.reader->IncPtr(size); db.reader->IncPtr(size);
} }
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionObject>(
CollectionObject &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
{
std::shared_ptr<Object> ob;
ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
dest.ob = ob.get();
}
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionChild>(
CollectionChild &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.collection, "*collection", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<Collection>(
Collection &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Fail>(dest.gobject, "gobject", db);
ReadField<ErrorPolicy_Fail>(dest.children, "children", db);
db.reader->IncPtr(size);
}
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
template <> template <>
void Structure ::Convert<MTex>( void Structure ::Convert<MTex>(
@ -297,7 +255,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 a hand-written exception that // This structure converter is therefore an hand-written exception that
// does it iteratively. // does it iteratively.
const int initial_pos = db.reader->GetCurrentPos(); const int initial_pos = db.reader->GetCurrentPos();
@ -565,7 +523,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_Warn>(dest.no, "no", db); ReadFieldArray<ErrorPolicy_Fail>(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);
@ -620,9 +578,7 @@ void Structure ::Convert<ListBase>(
const FileDatabase &db) const { const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db); ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db);
std::shared_ptr<ElemBase> last; ReadFieldPtr<ErrorPolicy_Igno>(dest.last, "*last", db);
ReadFieldPtr<ErrorPolicy_Igno>(last, "*last", db);
dest.last = last;
db.reader->IncPtr(size); db.reader->IncPtr(size);
} }
@ -646,9 +602,7 @@ void Structure ::Convert<ModifierData>(
const FileDatabase &db) const { const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db); ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db);
std::shared_ptr<ElemBase> prev; ReadFieldPtr<ErrorPolicy_Warn>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Warn>(prev, "*prev", db);
dest.prev = prev;
ReadField<ErrorPolicy_Igno>(dest.type, "type", db); ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db); ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db); ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db);
@ -706,7 +660,6 @@ void Structure ::Convert<Scene>(
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db); ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db); ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db); ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.master_collection, "*master_collection", db);
ReadField<ErrorPolicy_Igno>(dest.base, "base", db); ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
db.reader->IncPtr(size); db.reader->IncPtr(size);
@ -772,9 +725,7 @@ void Structure ::Convert<MirrorModifierData>(
ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db); ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db); ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db); ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db);
std::shared_ptr<Object> mirror_ob; ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob, "*mirror_ob", db);
ReadFieldPtr<ErrorPolicy_Igno>(mirror_ob, "*mirror_ob", db);
dest.mirror_ob = mirror_ob;
db.reader->IncPtr(size); db.reader->IncPtr(size);
} }
@ -835,9 +786,9 @@ void Structure::Convert<CustomDataLayer>(
ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db); ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Fail>(dest.active, "active", db); ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db); ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
ReadField<ErrorPolicy_Warn>(dest.active_clone, "active_clone", db); ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
ReadField<ErrorPolicy_Warn>(dest.active_mask, "active_mask", db); ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
ReadField<ErrorPolicy_Warn>(dest.uid, "uid", db); ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db); ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db); ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
@ -882,12 +833,6 @@ void DNA::RegisterConverters() {
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>); converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>); converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>); converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
converters["Collection"] = DNA::FactoryPair(&Structure::Allocate<Collection>, &Structure::Convert<Collection>);
converters["CollectionChild"] = DNA::FactoryPair(&Structure::Allocate<CollectionChild>, &Structure::Convert<CollectionChild>);
converters["CollectionObject"] = DNA::FactoryPair(&Structure::Allocate<CollectionObject>, &Structure::Convert<CollectionObject>);
} }
} // namespace Blender
} //namespace Assimp
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

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