replace NULL and avoid ai_assert with more than 2 tests.

pull/3296/head
Kim Kulling 2020-06-23 21:05:42 +02:00
commit 6205af4efb
659 changed files with 30283 additions and 48642 deletions

1
.github/FUNDING.yml vendored
View File

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

View File

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**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]
**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**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -7,40 +7,53 @@ on:
branches: [ master ]
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build .
- name: test
run: cd bin && ./unit
mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build .
- name: test
run: cd bin && ./unit
job:
name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
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.
include:
- name: windows-msvc
os: windows-latest
cxx: cl.exe
cc: cl.exe
- name: ubuntu-clang
os: ubuntu-latest
cxx: clang++
cc: clang
- name: macos-clang
os: macos-latest
cxx: clang++
cc: clang
- name: ubuntu-gcc
os: ubuntu-latest
cxx: g++
cc: gcc
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: configure
run: cmake CMakeLists.txt
- name: build
run: cmake --build . --config Release
- uses: actions/checkout@v2
- uses: lukka/get-cmake@latest
- uses: ilammy/msvc-dev-cmd@v1
- uses: lukka/set-shell-env@v1
with:
CXX: ${{ matrix.cxx }}
CC: ${{ matrix.cc }}
- name: configure and build
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: test
run: |
cd bin\Release
.\unit
run: cd build/bin && ./unit
shell: bash

56
.github/workflows/sanitizer.yml vendored 100644
View File

@ -0,0 +1,56 @@
name: C/C++ Sanitizer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
job1:
name: adress-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
CXX: clang++
CC: clang
- name: configure and build
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_ASAN=ON'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: test
run: cd build/bin && ./unit
shell: bash
job2:
name: undefined-behavior-sanitizer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: lukka/get-cmake@latest
- uses: lukka/set-shell-env@v1
with:
CXX: clang++
CC: clang
- name: configure and build
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_UBSAN=ON'
buildWithCMakeArgs: '-- -v'
buildDirectory: '${{ github.workspace }}/build/'
- name: test
run: cd build/bin && ./unit
shell: bash

6
.gitignore vendored
View File

@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/
tools/assimp_view/assimp_viewer.vcxproj.user
*.pyc
### Rust ###
# Generated by Cargo; will have compiled files and executables
port/assimp_rs/target/
# Backup files generated by rustfmt
port/assimp_rs/**/*.rs.bk
# Unix editor backups
*~
test/gtest/src/gtest-stamp/gtest-gitinfo.txt

View File

@ -108,10 +108,6 @@ OPTION ( ASSIMP_ERROR_MAX
"Enable all warnings."
OFF
)
OPTION ( ASSIMP_WERROR
"Treat warnings as errors."
OFF
)
OPTION ( ASSIMP_ASAN
"Enable AddressSanitizer."
OFF
@ -138,6 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF
)
IF ( WIN32 )
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)"
OFF )
ENDIF()
IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
IF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
@ -238,14 +240,19 @@ SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_M
SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
# Grouped compiler settings
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs)
ENDIF()
# Grouped compiler settings ########################################
IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
# hide all not-exported symbols
SET(CMAKE_CXX_FLAGS "-g -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(LIBSTDC++_LIBRARIES -lstdc++)
ELSEIF(MSVC)
@ -258,10 +265,10 @@ ELSEIF(MSVC)
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
SET(CMAKE_CXX_FLAGS "-g -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}")
ELSEIF( CMAKE_COMPILER_IS_MINGW )
IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
@ -306,16 +313,6 @@ IF (ASSIMP_ERROR_MAX)
ENDIF()
ENDIF()
IF (ASSIMP_WERROR)
MESSAGE(STATUS "Treating warnings as errors")
IF (MSVC)
ADD_COMPILE_OPTIONS(/WX)
ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
ENDIF()
ENDIF()
IF (ASSIMP_ASAN)
MESSAGE(STATUS "AddressSanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@ -521,19 +518,19 @@ ENDIF()
SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
"describe the current architecture."
)
IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
ELSE ()
IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
ELSE()
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
ENDIF ()
ENDIF()
# ${CMAKE_GENERATOR}
SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
"describe the current compiler."
)
IF ( ASSIMP_BUILD_COMPILER STREQUAL "")
ELSE ()
IF( ASSIMP_BUILD_COMPILER STREQUAL "")
ELSE()
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
ENDIF ()
ENDIF()
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )

100
INSTALL
View File

@ -1,50 +1,50 @@
========================================================================
Open Asset Import Library (assimp) INSTALL
========================================================================
------------------------------
Getting the documentation
------------------------------
A regularly-updated copy is available at
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
------------------------------
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
========================================================================
Open Asset Import Library (assimp) INSTALL
========================================================================
------------------------------
Getting the documentation
------------------------------
A regularly-updated copy is available at
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
------------------------------
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

@ -2,6 +2,7 @@ Open Asset Import Library (assimp)
==================================
A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
### Current project status ###
[![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)
[![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)
@ -179,6 +180,28 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
a pull request with your changes against the main repository's `master` branch.
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/assimp/assimp/graphs/contributors"><img src="https://opencollective.com/assimp/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/assimp/contribute)]
#### Individuals
<a href="https://opencollective.com/assimp"><img src="https://opencollective.com/assimp/individuals.svg?width=890"></a>
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/assimp/contribute)]
<a href="https://opencollective.com/assimp/organization/0/website"><img src="https://opencollective.com/assimp/organization/0/avatar.svg"></a>
### License ###
Our license is based on the modified, __3-clause BSD__-License.

View File

@ -7,6 +7,8 @@ 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}")
@ -35,8 +37,6 @@ if(MSVC)
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
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@")
@ -73,6 +73,9 @@ else()
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}"
@ -81,6 +84,9 @@ else()
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}"
)
@ -89,9 +95,6 @@ else()
endif()
endif()
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View File

@ -7,6 +7,8 @@ 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}")
@ -34,8 +36,6 @@ if(MSVC)
endif()
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
@ -56,7 +56,7 @@ if(MSVC)
# 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 "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
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}")
@ -73,6 +73,9 @@ else()
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}"
@ -81,6 +84,9 @@ else()
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}"
)

View File

@ -1,978 +0,0 @@
/*
---------------------------------------------------------------------------
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_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
// Header files, Assimp.
#include <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
// Header files, stdlib.
#include <iterator>
namespace Assimp
{
aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const
{
aiColor4D tcol;
// Check if stored data are supported.
if(!Composition.empty())
{
throw DeadlyImportError("IME. GetColor for composition");
}
else if(Color->Composed)
{
throw DeadlyImportError("IME. GetColor, composed color");
}
else
{
tcol = Color->Color;
}
// Check if default color must be used
if((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0))
{
tcol.r = 0.5f;
tcol.g = 0.5f;
tcol.b = 0.5f;
tcol.a = 1;
}
return tcol;
}
void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const
{
CAMFImporter_NodeElement_Vertices* vn = nullptr;
size_t col_idx;
// All data stored in "vertices", search for it.
for(CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices*)ne_child;
}
// If "vertices" not found then no work for us.
if(vn == nullptr) return;
pVertexCoordinateArray.reserve(vn->Child.size());// all coordinates stored as child and we need to reserve space for future push_back's.
pVertexColorArray.resize(vn->Child.size());// colors count equal vertices count.
col_idx = 0;
// Inside vertices collect all data and place to arrays
for(CAMFImporter_NodeElement* vn_child: vn->Child)
{
// vertices, colors
if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
{
// by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr;
for(CAMFImporter_NodeElement* vtx: vn_child->Child)
{
if(vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates)
{
pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates*)vtx)->Coordinate);
continue;
}
if(vtx->Type == CAMFImporter_NodeElement::ENET_Color)
{
pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color*)vtx;
continue;
}
}// for(CAMFImporter_NodeElement* vtx: vn_child->Child)
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& pID_R, const std::string& pID_G, const std::string& pID_B,
const std::string& pID_A)
{
size_t TextureConverted_Index;
std::string TextureConverted_ID;
// check input data
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)
{
if ( tex_convd.ID == TextureConverted_ID ) {
return TextureConverted_Index;
} else {
++TextureConverted_Index;
}
}
//
// Converted texture not found, create it.
//
CAMFImporter_NodeElement_Texture* src_texture[4]{nullptr};
std::vector<CAMFImporter_NodeElement_Texture*> src_texture_4check;
SPP_Texture converted_texture;
{// find all specified source textures
CAMFImporter_NodeElement* t_tex;
// R
if(!pID_R.empty())
{
if(!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
src_texture[0] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[0] = nullptr;
}
// G
if(!pID_G.empty())
{
if(!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
src_texture[1] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[1] = nullptr;
}
// B
if(!pID_B.empty())
{
if(!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
src_texture[2] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[2] = nullptr;
}
// A
if(!pID_A.empty())
{
if(!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
src_texture[3] = (CAMFImporter_NodeElement_Texture*)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
}
else
{
src_texture[3] = nullptr;
}
}// END: find all specified source textures
// check that all textures has same size
if(src_texture_4check.size() > 1)
{
for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
{
if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth))
{
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
}
}
}// if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture.Width = src_texture_4check[0]->Width;
converted_texture.Height = src_texture_4check[0]->Height;
converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false;
for(uint8_t i = 0; i < src_texture_4check.size(); i++) converted_texture.Tiled |= src_texture_4check[i]->Tiled;
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000");// copy initial string.
if(!pID_R.empty()) converted_texture.FormatHint[4] = '8';
if(!pID_G.empty()) converted_texture.FormatHint[5] = '8';
if(!pID_B.empty()) converted_texture.FormatHint[6] = '8';
if(!pID_A.empty()) converted_texture.FormatHint[7] = '8';
//
// Сopy data of textures.
//
size_t tex_size = 0;
size_t step = 0;
size_t off_g = 0;
size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied.
if(!pID_R.empty() && nullptr != src_texture[ 0 ] ) {
tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++;
}
if(!pID_G.empty() && nullptr != src_texture[ 1 ] ) {
tex_size += src_texture[1]->Data.size(); step++, off_b++;
}
if(!pID_B.empty() && nullptr != src_texture[ 2 ] ) {
tex_size += src_texture[2]->Data.size(); step++;
}
if(!pID_A.empty() && nullptr != src_texture[ 3 ] ) {
tex_size += src_texture[3]->Data.size(); step++;
}
// Create target array.
converted_texture.Data = new uint8_t[tex_size];
// And copy data
auto CopyTextureData = [&](const std::string& pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
{
if(!pID.empty())
{
for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
CAMFImporter_NodeElement_Texture* tex = src_texture[pSrcTexNum];
ai_assert(tex);
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
CopyTextureData(pID_R, 0, step, 0);
CopyTextureData(pID_G, off_g, step, 1);
CopyTextureData(pID_B, off_b, step, 2);
CopyTextureData(pID_A, step - 1, step, 3);
// Store new converted texture ID
converted_texture.ID = TextureConverted_ID;
// Store new converted texture
mTexture_Converted.push_back(converted_texture);
return TextureConverted_Index;
}
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated)
{
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) return false;
if(pTexMap2 == nullptr) return false;
if(pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
if(pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
if(pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
if(pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
return true;
};
pOutputList_Separated.clear();
if(pInputList.empty()) return;
do
{
SComplexFace face_start = pInputList.front();
std::list<SComplexFace> face_list_cur;
for(std::list<SComplexFace>::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;)
{
if(texmap_is_equal(face_start.TexMap, it->TexMap))
{
auto it_old = it;
++it;
face_list_cur.push_back(*it_old);
pInputList.erase(it_old);
}
else
{
++it;
}
}
if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
} while(!pInputList.empty());
}
void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& metadataList, aiNode& sceneNode) const
{
if ( !metadataList.empty() )
{
if(sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
// copy collected metadata to output node.
sceneNode.mMetaData = aiMetadata::Alloc( static_cast<unsigned int>(metadataList.size()) );
size_t meta_idx( 0 );
for(const CAMFImporter_NodeElement_Metadata& metadata: metadataList)
{
sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
}
}// if(!metadataList.empty())
}
void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode)
{
CAMFImporter_NodeElement_Color* object_color = nullptr;
// create new aiNode and set name as <object> has.
*pSceneNode = new aiNode;
(*pSceneNode)->mName = pNodeElement.ID;
// read mesh and color
for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
std::vector<aiVector3D> vertex_arr;
std::vector<CAMFImporter_NodeElement_Color*> color_arr;
// color for object
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color*)ne_child;
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh)
{
// Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh
Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
}
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
}
void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray,
const CAMFImporter_NodeElement_Color* pObjectColor, std::list<aiMesh*>& pMeshList, aiNode& pSceneNode)
{
std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it.
for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
{
const CAMFImporter_NodeElement_Color* ne_volume_color = nullptr;
const SPP_Material* cur_mat = nullptr;
if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
{
/******************* Get faces *******************/
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<std::list<SComplexFace> > complex_faces_toplist;// List of the face list for every mesh.
// check if volume use material
if(!ne_volume->MaterialID.empty())
{
if(!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID);
}
// inside "volume" collect all data and place to arrays or create new objects
for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
{
// color for volume
if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color)
{
ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color*>(ne_volume_child);
}
else if(ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle)// triangles, triangles colors
{
const CAMFImporter_NodeElement_Triangle& tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle*>(ne_volume_child);
SComplexFace complex_face;
// initialize pointers
complex_face.Color = nullptr;
complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates.
if(tri_al.Child.size())
{
for(const CAMFImporter_NodeElement* ne_triangle_child: tri_al.Child)
{
if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color)
complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color*>(ne_triangle_child);
else if(ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap*>(ne_triangle_child);
}
}// if(tri_al.Child.size())
// create new face and store it.
complex_face.Face.mNumIndices = 3;
complex_face.Face.mIndices = new unsigned int[3];
complex_face.Face.mIndices[0] = static_cast<unsigned int>(tri_al.V[0]);
complex_face.Face.mIndices[1] = static_cast<unsigned int>(tri_al.V[1]);
complex_face.Face.mIndices[2] = static_cast<unsigned int>(tri_al.V[2]);
complex_faces_list.push_back(complex_face);
}
}// for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
/**** Split faces list: one list per mesh ****/
PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist);
/***** Create mesh for every faces list ******/
for(std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
{
auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
{
size_t rv=0;
if(pBiggerThan != nullptr)
{
bool found = false;
for(const SComplexFace& face: pFaceList)
{
for(size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++)
{
if(face.Face.mIndices[idx_vert] > *pBiggerThan)
{
rv = face.Face.mIndices[idx_vert];
found = true;
break;
}
}
if(found) break;
}
if(!found) return *pBiggerThan;
}
else
{
rv = pFaceList.front().Face.mIndices[0];
}// if(pBiggerThan != nullptr) else
for(const SComplexFace& face: pFaceList)
{
for(size_t vi = 0; vi < face.Face.mNumIndices; vi++)
{
if(face.Face.mIndices[vi] < rv)
{
if(pBiggerThan != nullptr)
{
if(face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
}
else
{
rv = face.Face.mIndices[vi];
}
}
}
}// for(const SComplexFace& face: pFaceList)
return rv;
};// auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
{
for(const SComplexFace& face: pFaceList)
{
for(size_t vi = 0; vi < face.Face.mNumIndices; vi++)
{
if(face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast<unsigned int>(pIdx_To);
}
}
};// auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
{
// Color priorities(In descending order):
// 1. triangle color;
// 2. vertex color;
// 3. volume color;
// 4. object color;
// 5. material;
// 6. default - invisible coat.
//
// Fill vertices colors in color priority list above that's points from 1 to 6.
if((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr))// check for vertex color
{
if(pVertexColorArray[pIdx]->Composed)
throw DeadlyImportError("IME: vertex color composed");
else
return pVertexColorArray[pIdx]->Color;
}
else if(ne_volume_color != nullptr)// check for volume color
{
if(ne_volume_color->Composed)
throw DeadlyImportError("IME: volume color composed");
else
return ne_volume_color->Color;
}
else if(pObjectColor != nullptr)// check for object color
{
if(pObjectColor->Composed)
throw DeadlyImportError("IME: object color composed");
else
return pObjectColor->Color;
}
else if(cur_mat != nullptr)// check for material
{
return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z);
}
else// set default color.
{
return {0, 0, 0, 0};
}// if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else
};// auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
aiMesh* tmesh = new aiMesh;
tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;// Only triangles is supported by AMF.
//
// set geometry and colors (vertices)
//
// copy faces/triangles
tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
tmesh->mFaces = new aiFace[tmesh->mNumFaces];
// 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.
// 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.
std::vector<aiVector3D> vert_arr, texcoord_arr;
std::vector<aiColor4D> col_arr;
vert_arr.reserve(VertexCount_Max * 2);// "* 2" - see below TODO.
col_arr.reserve(VertexCount_Max * 2);
{// fill arrays
size_t vert_idx_from, vert_idx_to;
// first iteration.
vert_idx_to = 0;
vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr);
vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
// rest iterations
do
{
vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to);
if(vert_idx_from == vert_idx_to) break;// all indices are transferred,
vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
vert_idx_to++;
if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
} while(true);
}// fill arrays. END.
//
// check if triangle colors are used and create additional faces if needed.
//
for(const SComplexFace& face_cur: face_list_cur)
{
if(face_cur.Color != nullptr)
{
aiColor4D face_color;
size_t vert_idx_new = vert_arr.size();
if(face_cur.Color->Composed)
throw DeadlyImportError("IME: face color composed");
else
face_color = face_cur.Color->Color;
for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
{
vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind]));
col_arr.push_back(face_color);
face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(vert_idx_new++);
}
}// if(face_cur.Color != nullptr)
}// for(const SComplexFace& face_cur: face_list_cur)
//
// if texture is used then copy texture coordinates too.
//
if(face_list_cur.front().TexMap != nullptr)
{
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
/// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
/// optimisation.
bool* idx_vert_used;
idx_vert_used = new bool[VertexCount_Max * 2];
for(size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++) idx_vert_used[i] = false;
// This ID's will be used when set materials ID in scene.
tmesh->mMaterialIndex = static_cast<unsigned int>(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R,
face_list_cur.front().TexMap->TextureID_G,
face_list_cur.front().TexMap->TextureID_B,
face_list_cur.front().TexMap->TextureID_A));
texcoord_arr.resize(VertexCount_Max * 2);
for(const SComplexFace& face_cur: face_list_cur)
{
for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
{
const size_t idx_vert = face_cur.Face.mIndices[idx_ind];
if(!idx_vert_used[idx_vert])
{
texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind];
idx_vert_used[idx_vert] = true;
}
else if(texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind])
{
// in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture
// coordinates.
vert_arr.push_back(vert_arr.at(idx_vert));
col_arr.push_back(col_arr.at(idx_vert));
texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind];
face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(idx_vert_new++);
}
}// for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
}// for(const SComplexFace& face_cur: face_list_cur)
delete [] idx_vert_used;
// shrink array
texcoord_arr.resize(idx_vert_new);
}// if(face_list_cur.front().TexMap != nullptr)
//
// copy collected data to mesh
//
tmesh->mNumVertices = static_cast<unsigned int>(vert_arr.size());
tmesh->mVertices = new aiVector3D[tmesh->mNumVertices];
tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices];
memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D));
if(texcoord_arr.size() > 0)
{
tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices];
memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
tmesh->mNumUVComponents[0] = 2;// U and V stored in "x", "y" of aiVector3D.
}
size_t idx_face = 0;
for(const SComplexFace& face_cur: face_list_cur) tmesh->mFaces[idx_face++] = face_cur.Face;
// store new aiMesh
mesh_idx.push_back(static_cast<unsigned int>(pMeshList.size()));
pMeshList.push_back(tmesh);
}// for(const std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
}// if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
// if meshes was created then assign new indices with current aiNode
if(!mesh_idx.empty())
{
std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
pSceneNode.mNumMeshes = static_cast<unsigned int>(mesh_idx.size());
pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *mit++;
}// if(mesh_idx.size() > 0)
}
void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial)
{
SPP_Material new_mat;
new_mat.ID = pMaterial.ID;
for(const CAMFImporter_NodeElement* mat_child: pMaterial.Child)
{
if(mat_child->Type == CAMFImporter_NodeElement::ENET_Color)
{
new_mat.Color = (CAMFImporter_NodeElement_Color*)mat_child;
}
else if(mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata)
{
new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata*)mat_child);
}
}// for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
// place converted material to special list
mMaterial_Converted.push_back(new_mat);
}
void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const
{
aiNode* con_node;
std::list<aiNode*> ch_node;
// We will build next hierarchy:
// aiNode as parent (<constellation>) for set of nodes as a children
// |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
// ...
// \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
con_node = new aiNode;
con_node->mName = pConstellation.ID;
// Walk through children and search for instances of another objects, constellations.
for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
{
aiMatrix4x4 tmat;
aiNode* t_node;
aiNode* found_node;
if(ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue;
if(ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for conveniance
CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);
// find referenced object
if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation
t_node = new aiNode;
t_node->mParent = con_node;
// apply transformation
aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
// create array for one child node
t_node->mNumChildren = 1;
t_node->mChildren = new aiNode*[t_node->mNumChildren];
SceneCombiner::Copy(&t_node->mChildren[0], found_node);
t_node->mChildren[0]->mParent = t_node;
ch_node.push_back(t_node);
}// for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
// copy found aiNode's as children
if(ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
size_t ch_idx = 0;
con_node->mNumChildren = static_cast<unsigned int>(ch_node.size());
con_node->mChildren = new aiNode*[con_node->mNumChildren];
for(aiNode* node: ch_node) con_node->mChildren[ch_idx++] = node;
// and place "root" of <constellation> node to node list
pNodeList.push_back(con_node);
}
void AMFImporter::Postprocess_BuildScene(aiScene* pScene)
{
std::list<aiNode*> node_list;
std::list<aiMesh*> mesh_list;
std::list<CAMFImporter_NodeElement_Metadata*> meta_list;
//
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
// For building aiScene we are must to do few steps:
// at first creating root node for aiScene.
pScene->mRootNode = new aiNode;
pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
// search for root(<amf>) element
CAMFImporter_NodeElement* root_el = nullptr;
for(CAMFImporter_NodeElement* ne: mNodeElement_List)
{
if(ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
root_el = ne;
break;
}// for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found.
if(root_el == nullptr) 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>,
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
// at any moment.
//
// 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
for(const CAMFImporter_NodeElement* root_child: root_el->Child)
{
if(root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material*)root_child));
}
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
//
// 3. <object>
for(const CAMFImporter_NodeElement* root_child: root_el->Child)
{
if(root_child->Type == CAMFImporter_NodeElement::ENET_Object)
{
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>
Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object*)root_child), mesh_list, &tnode);
if(tnode != nullptr) node_list.push_back(tnode);
}
}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes.
//
for(const CAMFImporter_NodeElement* root_child: root_el->Child)
{
// 4. <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.
Postprocess_BuildConstellation(*((CAMFImporter_NodeElement_Constellation*)root_child), node_list);
}
// 5, <metadata>
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)
// at now we can add collected metadata to root node
Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
//
// Check constellation children
//
// As said in specification:
// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
// And at this step we are checking that relations.
nl_clean_loop:
if(node_list.size() > 1)
{
// walk through all nodes
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.
std::list<aiNode*>::const_iterator next_it = nl_it;
++next_it;
for(; next_it != node_list.end(); ++next_it)
{
if((*next_it)->FindNode((*nl_it)->mName) != nullptr)
{
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
node_list.erase(nl_it);
goto nl_clean_loop;
}
}// for(; next_it != node_list.end(); next_it++)
}// for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
}
//
// move created objects to aiScene
//
//
// Nodes
if(!node_list.empty())
{
std::list<aiNode*>::const_iterator nl_it = node_list.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
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
// mRootNode only as parent.
(*nl_it)->mParent = pScene->mRootNode;
pScene->mRootNode->mChildren[i] = *nl_it++;
}
}// if(node_list.size() > 0)
//
// Meshes
if(!mesh_list.empty())
{
std::list<aiMesh*>::const_iterator ml_it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *ml_it++;
}// if(mesh_list.size() > 0)
//
// Textures
pScene->mNumTextures = static_cast<unsigned int>(mTexture_Converted.size());
if(pScene->mNumTextures > 0)
{
size_t idx;
idx = 0;
pScene->mTextures = new aiTexture*[pScene->mNumTextures];
for(const SPP_Texture& tex_convd: mTexture_Converted)
{
pScene->mTextures[idx] = new aiTexture;
pScene->mTextures[idx]->mWidth = static_cast<unsigned int>(tex_convd.Width);
pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
pScene->mTextures[idx]->pcData = (aiTexel*)tex_convd.Data;
// texture format description.
strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
idx++;
}// for(const SPP_Texture& tex_convd: mTexture_Converted)
// Create materials for embedded textures.
idx = 0;
pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size());
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
for(const SPP_Texture& tex_convd: mTexture_Converted)
{
const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx));
const int mode = aiTextureOp_Multiply;
const int repeat = tex_convd.Tiled ? 1 : 0;
pScene->mMaterials[idx] = new aiMaterial;
pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
idx++;
}
}// if(pScene->mNumTextures > 0)
}// END: after that walk through children of root and collect data
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

View File

@ -43,120 +43,117 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
#include "3DS/3DSExporter.h"
#include "3DS/3DSLoader.h"
#include "3DS/3DSHelper.h"
#include "AssetLib/3DS/3DSExporter.h"
#include "AssetLib/3DS/3DSHelper.h"
#include "AssetLib/3DS/3DSLoader.h"
#include "PostProcessing/SplitLargeMeshes.h"
#include <assimp/SceneCombiner.h>
#include <assimp/StringComparison.h>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp;
namespace Assimp {
namespace Assimp {
using namespace D3DS;
namespace {
//////////////////////////////////////////////////////////////////////////////////////
// Scope utility to write a 3DS file chunk.
//
// Upon construction, the chunk header is written with the chunk type (flags)
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
// size based on the then-position of the output stream cursor is filled in.
class ChunkWriter {
enum {
CHUNK_SIZE_NOT_SET = 0xdeadbeef
, SIZE_OFFSET = 2
};
public:
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
: writer(writer)
{
chunk_start_pos = writer.GetCurrentPos();
writer.PutU2(chunk_type);
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
}
~ChunkWriter() {
std::size_t head_pos = writer.GetCurrentPos();
ai_assert(head_pos > chunk_start_pos);
const std::size_t chunk_size = head_pos - chunk_start_pos;
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
writer.PutU4(static_cast<uint32_t>(chunk_size));
writer.SetCurrentPos(head_pos);
}
private:
StreamWriterLE& writer;
std::size_t chunk_start_pos;
//////////////////////////////////////////////////////////////////////////////////////
// Scope utility to write a 3DS file chunk.
//
// Upon construction, the chunk header is written with the chunk type (flags)
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
// size based on the then-position of the output stream cursor is filled in.
class ChunkWriter {
enum {
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
SIZE_OFFSET = 2
};
// Return an unique name for a given |mesh| attached to |node| that
// preserves the mesh's given name if it has one. |index| is the index
// of the mesh in |aiScene::mMeshes|.
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
static const std::string underscore = "_";
char postfix[10] = {0};
ASSIMP_itoa10(postfix, index);
std::string result = node.mName.C_Str();
if (mesh.mName.length > 0) {
result += underscore + mesh.mName.C_Str();
}
return result + underscore + postfix;
public:
ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
writer(writer) {
chunk_start_pos = writer.GetCurrentPos();
writer.PutU2(chunk_type);
writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
}
// Return an unique name for a given |mat| with original position |index|
// in |aiScene::mMaterials|. The name preserves the original material
// name if possible.
std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
static const std::string underscore = "_";
char postfix[10] = {0};
ASSIMP_itoa10(postfix, index);
~ChunkWriter() {
std::size_t head_pos = writer.GetCurrentPos();
aiString mat_name;
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
return mat_name.C_Str() + underscore + postfix;
}
ai_assert(head_pos > chunk_start_pos);
const std::size_t chunk_size = head_pos - chunk_start_pos;
return "Material" + underscore + postfix;
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
writer.PutU4(static_cast<uint32_t>(chunk_size));
writer.SetCurrentPos(head_pos);
}
// Collect world transformations for each node
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
trafos[node] = parent * node->mTransformation;
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectTrafos(node->mChildren[i], trafos);
}
private:
StreamWriterLE &writer;
std::size_t chunk_start_pos;
};
// Return an unique name for a given |mesh| attached to |node| that
// preserves the mesh's given name if it has one. |index| is the index
// of the mesh in |aiScene::mMeshes|.
std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) {
static const std::string underscore = "_";
char postfix[10] = { 0 };
ASSIMP_itoa10(postfix, index);
std::string result = node.mName.C_Str();
if (mesh.mName.length > 0) {
result += underscore + mesh.mName.C_Str();
}
return result + underscore + postfix;
}
// Return an unique name for a given |mat| with original position |index|
// in |aiScene::mMaterials|. The name preserves the original material
// name if possible.
std::string GetMaterialName(const aiMaterial &mat, unsigned int index) {
static const std::string underscore = "_";
char postfix[10] = { 0 };
ASSIMP_itoa10(postfix, index);
aiString mat_name;
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
return mat_name.C_Str() + underscore + postfix;
}
// Generate a flat list of the meshes (by index) assigned to each node
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
meshes.insert(std::make_pair(node, node->mMeshes[i]));
}
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectMeshes(node->mChildren[i], meshes);
}
return "Material" + underscore + postfix;
}
// Collect world transformations for each node
void CollectTrafos(const aiNode *node, std::map<const aiNode *, aiMatrix4x4> &trafos) {
const aiMatrix4x4 &parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
trafos[node] = parent * node->mTransformation;
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectTrafos(node->mChildren[i], trafos);
}
}
// Generate a flat list of the meshes (by index) assigned to each node
void CollectMeshes(const aiNode *node, std::multimap<const aiNode *, unsigned int> &meshes) {
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
meshes.insert(std::make_pair(node, node->mMeshes[i]));
}
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectMeshes(node->mChildren[i], meshes);
}
}
} // namespace
// ------------------------------------------------------------------------------------------------
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
{
std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
if(!outfile) {
void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
std::shared_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
if (!outfile) {
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
}
@ -167,8 +164,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
// SplitLargeMeshes can do this, but it requires the correct limit to be set
// which is not possible with the current way of specifying preprocess steps
// in |Exporter::ExportFormatEntry|.
aiScene* scenecopy_tmp;
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
aiScene *scenecopy_tmp;
SceneCombiner::CopyScene(&scenecopy_tmp, pScene);
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
SplitLargeMeshesProcess_Triangle tri_splitter;
@ -186,10 +183,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
: scene(scene)
, writer(outfile)
{
Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene *scene) :
scene(scene), writer(outfile) {
CollectTrafos(scene->mRootNode, trafos);
CollectMeshes(scene->mRootNode, meshes);
@ -217,10 +212,8 @@ 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) {
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
{
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
@ -237,7 +230,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
int16_t hierarchy_pos = static_cast<int16_t>(seq);
if (sibling_level != -1) {
hierarchy_pos =(uint16_t) sibling_level;
hierarchy_pos = (uint16_t)sibling_level;
}
// Write the hierarchy position
@ -260,7 +253,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
const bool first_child = node.mNumChildren == 0 && i == 0;
const unsigned int mesh_idx = node.mMeshes[i];
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
{
@ -276,15 +269,14 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMaterials()
{
void Discreet3DSExporter::WriteMaterials() {
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
const aiMaterial& mat = *scene->mMaterials[i];
const aiMaterial &mat = *scene->mMaterials[i];
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
const std::string& name = GetMaterialName(mat, i);
const std::string &name = GetMaterialName(mat, i);
WriteString(name);
}
@ -314,7 +306,7 @@ void Discreet3DSExporter::WriteMaterials()
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
Discreet3DS::shadetype3ds shading_mode_out;
switch(shading_mode) {
switch (shading_mode) {
case aiShadingMode_Flat:
case aiShadingMode_NoShading:
shading_mode_out = Discreet3DS::Flat;
@ -341,7 +333,6 @@ void Discreet3DSExporter::WriteMaterials()
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
}
float f;
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
@ -370,14 +361,13 @@ void Discreet3DSExporter::WriteMaterials()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
{
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
aiString path;
aiTextureMapMode map_mode[2] = {
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
};
ai_real blend = 1.0;
if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
return;
}
@ -400,8 +390,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
uint16_t val = 0; // WRAP
if (map_mode[0] == aiTextureMapMode_Mirror) {
val = 0x2;
}
else if (map_mode[0] == aiTextureMapMode_Decal) {
} else if (map_mode[0] == aiTextureMapMode_Decal) {
val = 0x10;
}
writer.PutU2(val);
@ -410,8 +399,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMeshes()
{
void Discreet3DSExporter::WriteMeshes() {
// NOTE: 3DS allows for instances. However:
// i) not all importers support reading them
// ii) instances are not as flexible as they are in assimp, in particular,
@ -423,25 +411,24 @@ void Discreet3DSExporter::WriteMeshes()
// Furthermore, the TRIMESH is transformed into world space so that it will
// appear correctly if importers don't read the scene hierarchy at all.
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
const aiNode& node = *(*it).first;
const aiNode &node = *(*it).first;
const unsigned int mesh_idx = (*it).second;
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
const aiMesh &mesh = *scene->mMeshes[mesh_idx];
// This should not happen if the SLM step is correctly executed
// before the scene is handed to the exporter
ai_assert(mesh.mNumVertices <= 0xffff);
ai_assert(mesh.mNumFaces <= 0xffff);
const aiMatrix4x4& trafo = trafos[&node];
const aiMatrix4x4 &trafo = trafos[&node];
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
// Mesh name is tied to the node it is attached to so it can later be referenced
const std::string& name = GetMeshName(mesh, mesh_idx, node);
const std::string &name = GetMeshName(mesh, mesh_idx, node);
WriteString(name);
// TRIMESH chunk
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
@ -452,7 +439,7 @@ void Discreet3DSExporter::WriteMeshes()
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D& v = trafo * mesh.mVertices[i];
const aiVector3D &v = trafo * mesh.mVertices[i];
writer.PutF4(v.x);
writer.PutF4(v.y);
writer.PutF4(v.z);
@ -466,7 +453,7 @@ void Discreet3DSExporter::WriteMeshes()
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D& v = mesh.mTextureCoords[0][i];
const aiVector3D &v = mesh.mTextureCoords[0][i];
writer.PutF4(v.x);
writer.PutF4(v.y);
}
@ -481,7 +468,7 @@ void Discreet3DSExporter::WriteMeshes()
// Count triangles, discard lines and points
uint16_t count = 0;
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
const aiFace& f = mesh.mFaces[i];
const aiFace &f = mesh.mFaces[i];
if (f.mNumIndices < 3) {
continue;
}
@ -492,7 +479,7 @@ void Discreet3DSExporter::WriteMeshes()
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
const aiFace& f = mesh.mFaces[i];
const aiFace &f = mesh.mFaces[i];
if (f.mNumIndices < 3) {
continue;
}
@ -524,10 +511,9 @@ void Discreet3DSExporter::WriteMeshes()
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
{
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT);
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
WriteString(name);
// Because assimp splits meshes by material, only a single
@ -542,7 +528,7 @@ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteString(const std::string& s) {
void Discreet3DSExporter::WriteString(const std::string &s) {
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
writer.PutI1(*it);
}
@ -550,7 +536,7 @@ void Discreet3DSExporter::WriteString(const std::string& s) {
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteString(const aiString& s) {
void Discreet3DSExporter::WriteString(const aiString &s) {
for (std::size_t i = 0; i < s.length; ++i) {
writer.PutI1(s.data[i]);
}
@ -558,7 +544,7 @@ void Discreet3DSExporter::WriteString(const aiString& s) {
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
void Discreet3DSExporter::WriteColor(const aiColor3D &color) {
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF);
writer.PutF4(color.r);
writer.PutF4(color.g);
@ -577,6 +563,5 @@ void Discreet3DSExporter::WritePercentChunk(double f) {
writer.PutF8(f);
}
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -322,7 +322,7 @@ struct Face : public FaceWithSmoothingGroup {
};
#ifdef _WIN32
# pragma warning(disable : 4315)
#pragma warning(disable : 4315)
#endif
// ---------------------------------------------------------------------------
@ -441,30 +441,50 @@ struct Material {
// empty
}
Material(const Material &other) = default;
Material &operator=(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
}
//! 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)) {
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 {
@ -593,7 +613,12 @@ struct Node {
Node() = delete;
explicit Node(const std::string &name) :
mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) {
mParent(nullptr),
mName(name),
mInstanceNumber(0),
mHierarchyPos(0),
mHierarchyIndex(0),
mInstanceCount(1) {
aRotationKeys.reserve(20);
aPositionKeys.reserve(20);
aScalingKeys.reserve(20);

File diff suppressed because it is too large Load Diff

View File

@ -65,15 +65,11 @@ using namespace D3DS;
// ---------------------------------------------------------------------------------
/** Importer class for 3D Studio r3 and r4 3DS files
*/
class Discreet3DSImporter : public BaseImporter
{
class Discreet3DSImporter : public BaseImporter {
public:
Discreet3DSImporter();
~Discreet3DSImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.

View File

@ -44,81 +44,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFExporter.h"
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/StringUtils.h>
#include <assimp/Exceptional.h>
#include <assimp/StringUtils.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#ifdef ASSIMP_USE_HUNTER
# include <zip/zip.h>
#include <zip/zip.h>
#else
# include <contrib/zip/src/zip.h>
#include <contrib/zip/src/zip.h>
#endif
namespace Assimp {
void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) {
if ( nullptr == pIOSystem ) {
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
if (nullptr == pIOSystem) {
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
}
D3MF::D3MFExporter myExporter( pFile, pScene );
if ( myExporter.validate() ) {
if ( pIOSystem->Exists( pFile ) ) {
if ( !pIOSystem->DeleteFile( pFile ) ) {
throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) );
D3MF::D3MFExporter myExporter(pFile, pScene);
if (myExporter.validate()) {
if (pIOSystem->Exists(pFile)) {
if (!pIOSystem->DeleteFile(pFile)) {
throw DeadlyExportError("File exists, cannot override : " + std::string(pFile));
}
}
bool ok = myExporter.exportArchive(pFile);
if ( !ok ) {
throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
if (!ok) {
throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
}
}
}
namespace D3MF {
D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
: mArchiveName( pFile )
, m_zipArchive( nullptr )
, mScene( pScene )
, mModelOutput()
, mRelOutput()
, mContentOutput()
, mBuildItems()
, mRelations() {
D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
// empty
}
D3MFExporter::~D3MFExporter() {
for ( size_t i = 0; i < mRelations.size(); ++i ) {
delete mRelations[ i ];
for (size_t i = 0; i < mRelations.size(); ++i) {
delete mRelations[i];
}
mRelations.clear();
}
bool D3MFExporter::validate() {
if ( mArchiveName.empty() ) {
if (mArchiveName.empty()) {
return false;
}
if ( nullptr == mScene ) {
if (nullptr == mScene) {
return false;
}
return true;
}
bool D3MFExporter::exportArchive( const char *file ) {
bool ok( true );
bool D3MFExporter::exportArchive(const char *file) {
bool ok(true);
m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' );
if ( nullptr == m_zipArchive ) {
m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
if (nullptr == m_zipArchive) {
return false;
}
@ -126,7 +119,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
ok |= export3DModel();
ok |= exportRelations();
zip_close( m_zipArchive );
zip_close(m_zipArchive);
m_zipArchive = nullptr;
return ok;
@ -145,7 +138,7 @@ bool D3MFExporter::exportContentTypes() {
mContentOutput << std::endl;
mContentOutput << "</Types>";
mContentOutput << std::endl;
exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
return true;
}
@ -157,20 +150,20 @@ bool D3MFExporter::exportRelations() {
mRelOutput << std::endl;
mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
for ( size_t i = 0; i < mRelations.size(); ++i ) {
if ( mRelations[ i ]->target[ 0 ] == '/' ) {
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
for (size_t i = 0; i < mRelations.size(); ++i) {
if (mRelations[i]->target[0] == '/') {
mRelOutput << "<Relationship Target=\"" << mRelations[i]->target << "\" ";
} else {
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
mRelOutput << "<Relationship Target=\"/" << mRelations[i]->target << "\" ";
}
mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
mRelOutput << "Type=\"" << mRelations[i]->type << "\" />";
mRelOutput << std::endl;
}
mRelOutput << "</Relationships>";
mRelOutput << std::endl;
writeRelInfoToFile( "_rels", ".rels" );
writeRelInfoToFile("_rels", ".rels");
mRelOutput.flush();
return true;
@ -181,8 +174,8 @@ bool D3MFExporter::export3DModel() {
writeHeader();
mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\""
<< "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
<< std::endl;
<< " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
<< std::endl;
mModelOutput << "<" << XmlTag::resources << ">";
mModelOutput << std::endl;
@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
writeObjects();
mModelOutput << "</" << XmlTag::resources << ">";
mModelOutput << std::endl;
writeBuild();
@ -203,36 +195,36 @@ bool D3MFExporter::export3DModel() {
info->id = "rel0";
info->target = "/3D/3DModel.model";
info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
mRelations.push_back( info );
mRelations.push_back(info);
writeModelToArchive( "3D", "3DModel.model" );
writeModelToArchive("3D", "3DModel.model");
mModelOutput.flush();
return true;
}
void D3MFExporter::writeHeader() {
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
mModelOutput << std::endl;
}
void D3MFExporter::writeMetaData() {
if ( nullptr == mScene->mMetaData ) {
if (nullptr == mScene->mMetaData) {
return;
}
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
if ( 0 == numMetaEntries ) {
const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties);
if (0 == numMetaEntries) {
return;
}
const aiString *key = nullptr;
const aiString *key = nullptr;
const aiMetadataEntry *entry(nullptr);
for ( size_t i = 0; i < numMetaEntries; ++i ) {
mScene->mMetaData->Get( i, key, entry );
std::string k( key->C_Str() );
for (size_t i = 0; i < numMetaEntries; ++i) {
mScene->mMetaData->Get(i, key, entry);
std::string k(key->C_Str());
aiString value;
mScene->mMetaData->Get( k, value );
mScene->mMetaData->Get(k, value);
mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
mModelOutput << value.C_Str();
mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
@ -241,103 +233,114 @@ void D3MFExporter::writeMetaData() {
void D3MFExporter::writeBaseMaterials() {
mModelOutput << "<basematerials id=\"1\">\n";
std::string strName, hexDiffuseColor , tmp;
for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
aiMaterial *mat = mScene->mMaterials[ i ];
std::string strName, hexDiffuseColor, tmp;
for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
aiMaterial *mat = mScene->mMaterials[i];
aiString name;
if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
strName = "basemat_" + to_string( i );
if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
strName = "basemat_" + to_string(i);
} else {
strName = name.C_Str();
}
aiColor4D color;
if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
hexDiffuseColor.clear();
tmp.clear();
hexDiffuseColor = "#";
tmp = DecimalToHexa( (ai_real) color.r );
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.g);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.b);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.a);
hexDiffuseColor += tmp;
// rgbs %
if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
hexDiffuseColor = Rgba2Hex(
(int)((ai_real)color.r) * 255,
(int)((ai_real)color.g) * 255,
(int)((ai_real)color.b) * 255,
(int)((ai_real)color.a) * 255,
true);
} else {
hexDiffuseColor = "#";
tmp = DecimalToHexa((ai_real)color.r);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.g);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.b);
hexDiffuseColor += tmp;
tmp = DecimalToHexa((ai_real)color.a);
hexDiffuseColor += tmp;
}
} else {
hexDiffuseColor = "#FFFFFFFF";
}
mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
mModelOutput << "<base name=\"" + strName + "\" " + " displaycolor=\"" + hexDiffuseColor + "\" />\n";
}
mModelOutput << "</basematerials>\n";
}
void D3MFExporter::writeObjects() {
if ( nullptr == mScene->mRootNode ) {
if (nullptr == mScene->mRootNode) {
return;
}
aiNode *root = mScene->mRootNode;
for ( unsigned int i = 0; i < root->mNumChildren; ++i ) {
aiNode *currentNode( root->mChildren[ i ] );
if ( nullptr == currentNode ) {
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
aiNode *currentNode(root->mChildren[i]);
if (nullptr == currentNode) {
continue;
}
mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
mModelOutput << std::endl;
for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) {
aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ];
if ( nullptr == currentMesh ) {
for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
if (nullptr == currentMesh) {
continue;
}
writeMesh( currentMesh );
writeMesh(currentMesh);
}
mBuildItems.push_back( i );
mBuildItems.push_back(i);
mModelOutput << "</" << XmlTag::object << ">";
mModelOutput << std::endl;
}
}
void D3MFExporter::writeMesh( aiMesh *mesh ) {
if ( nullptr == mesh ) {
void D3MFExporter::writeMesh(aiMesh *mesh) {
if (nullptr == mesh) {
return;
}
mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) {
writeVertex( mesh->mVertices[ i ] );
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
writeVertex(mesh->mVertices[i]);
}
mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
const unsigned int matIdx( mesh->mMaterialIndex );
const unsigned int matIdx(mesh->mMaterialIndex);
writeFaces( mesh, matIdx );
writeFaces(mesh, matIdx);
mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
}
void D3MFExporter::writeVertex( const aiVector3D &pos ) {
void D3MFExporter::writeVertex(const aiVector3D &pos) {
mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
mModelOutput << std::endl;
}
void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
if ( nullptr == mesh ) {
void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
if (nullptr == mesh) {
return;
}
if ( !mesh->HasFaces() ) {
if (!mesh->HasFaces()) {
return;
}
mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
aiFace &currentFace = mesh->mFaces[ i ];
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
<< currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
<< "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
aiFace &currentFace = mesh->mFaces[i];
mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
<< currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
<< "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />";
mModelOutput << std::endl;
}
mModelOutput << "</" << XmlTag::triangles << ">";
@ -347,54 +350,53 @@ void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
void D3MFExporter::writeBuild() {
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
for ( size_t i = 0; i < mBuildItems.size(); ++i ) {
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
for (size_t i = 0; i < mBuildItems.size(); ++i) {
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
mModelOutput << std::endl;
}
mModelOutput << "</" << XmlTag::build << ">";
mModelOutput << std::endl;
}
void D3MFExporter::exportContentTyp( const std::string &filename ) {
if ( nullptr == m_zipArchive ) {
throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
void D3MFExporter::exportContentTyp(const std::string &filename) {
if (nullptr == m_zipArchive) {
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());
const std::string &exportTxt( mContentOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
const std::string &exportTxt(mContentOutput.str());
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
zip_entry_close( m_zipArchive );
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." );
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() );
zip_entry_open(m_zipArchive, entry.c_str());
const std::string &exportTxt( mModelOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
const std::string &exportTxt(mModelOutput.str());
zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
zip_entry_close( m_zipArchive );
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." );
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() );
zip_entry_open(m_zipArchive, entry.c_str());
const std::string &exportTxt( mRelOutput.str() );
zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
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);
}
} // Namespace D3MF
} // Namespace Assimp

View File

@ -44,24 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFImporter.h"
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <assimp/StringComparison.h>
#include <assimp/StringUtils.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <memory>
#include "D3MFOpcPackage.h"
#include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h>
#include <assimp/irrXMLWrapper.h>
#include <iomanip>
@ -70,90 +70,90 @@ namespace D3MF {
class XmlSerializer {
public:
using MatArray = std::vector<aiMaterial*>;
using MatArray = std::vector<aiMaterial *>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
XmlSerializer(XmlReader* xmlReader)
: mMeshes()
, mMatArray()
, mActiveMatGroup( 99999999 )
, mMatId2MatArray()
, xmlReader(xmlReader){
// empty
XmlSerializer(XmlReader *xmlReader) :
mMeshes(),
mMatArray(),
mActiveMatGroup(99999999),
mMatId2MatArray(),
xmlReader(xmlReader) {
// empty
}
~XmlSerializer() {
// empty
}
void ImportXml(aiScene* scene) {
if ( nullptr == scene ) {
void ImportXml(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mRootNode = new aiNode();
std::vector<aiNode*> children;
std::vector<aiNode *> children;
std::string nodeName;
while(ReadToEndElement(D3MF::XmlTag::model)) {
while (ReadToEndElement(D3MF::XmlTag::model)) {
nodeName = xmlReader->getNodeName();
if( nodeName == D3MF::XmlTag::object) {
if (nodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(scene));
} else if( nodeName == D3MF::XmlTag::build) {
//
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
} else if (nodeName == D3MF::XmlTag::build) {
//
} else if (nodeName == D3MF::XmlTag::basematerials) {
ReadBaseMaterials();
} else if ( nodeName == D3MF::XmlTag::meta ) {
} else if (nodeName == D3MF::XmlTag::meta) {
ReadMetadata();
}
}
if ( scene->mRootNode->mName.length == 0 ) {
scene->mRootNode->mName.Set( "3MF" );
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 );
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);
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 );
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]();
scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
}
private:
aiNode* ReadObject(aiScene* scene) {
aiNode *ReadObject(aiScene *scene) {
std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds;
const char *attrib( nullptr );
const char *attrib(nullptr);
std::string name, type;
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
if ( nullptr != attrib ) {
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
if (nullptr != attrib) {
name = attrib;
}
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
if ( nullptr != attrib ) {
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
if (nullptr != attrib) {
type = attrib;
}
@ -162,8 +162,8 @@ private:
size_t meshIdx = mMeshes.size();
while(ReadToEndElement(D3MF::XmlTag::object)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
while (ReadToEndElement(D3MF::XmlTag::object)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh();
mesh->mName.Set(name);
@ -183,11 +183,11 @@ private:
}
aiMesh *ReadMesh() {
aiMesh* mesh = new aiMesh();
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
aiMesh *mesh = new aiMesh();
while (ReadToEndElement(D3MF::XmlTag::mesh)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
ImportVertices(mesh);
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
ImportTriangles(mesh);
}
}
@ -196,24 +196,24 @@ private:
}
void ReadMetadata() {
const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
xmlReader->read();
const std::string value = xmlReader->getNodeData();
if ( name.empty() ) {
if (name.empty()) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back( entry );
mMetaData.push_back(entry);
}
void ImportVertices(aiMesh* mesh) {
void ImportVertices(aiMesh *mesh) {
std::vector<aiVector3D> vertices;
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
while (ReadToEndElement(D3MF::XmlTag::vertices)) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex());
}
}
@ -233,20 +233,20 @@ private:
return vertex;
}
void ImportTriangles(aiMesh* mesh) {
std::vector<aiFace> faces;
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;
}
}
}
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];
@ -269,117 +269,115 @@ private:
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 ) {
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 ) {
MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
if (mMatId2MatArray.end() == it) {
MatIdArray.clear();
mMatId2MatArray[ id ] = MatIdArray;
mMatId2MatArray[id] = MatIdArray;
} else {
MatIdArray = it->second;
}
}
MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
mMatId2MatArray[mActiveMatGroup] = MatIdArray;
}
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
mMatArray.push_back( readMaterialDef() );
while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
mMatArray.push_back(readMaterialDef());
}
}
bool parseColor( const char *color, aiColor4D &diffuse ) {
if ( nullptr == color ) {
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) {
const size_t len(strlen(color));
if (9 != len && 7 != len) {
return false;
}
const char *buf( color );
if ( '#' != *buf ) {
const char *buf(color);
if ('#' != *buf) {
return false;
}
++buf;
char comp[ 3 ] = { 0,0,'\0' };
char comp[3] = { 0, 0, '\0' };
comp[ 0 ] = *buf;
comp[0] = *buf;
++buf;
comp[ 1 ] = *buf;
comp[1] = *buf;
++buf;
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
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;
comp[0] = *buf;
++buf;
comp[ 1 ] = *buf;
comp[1] = *buf;
++buf;
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
diffuse.b = 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, NULL, 16 ) ) / ai_real(255.0);
if(7 == len)
if (7 == len)
return true;
comp[ 0 ] = *buf;
comp[0] = *buf;
++buf;
comp[ 1 ] = *buf;
comp[1] = *buf;
++buf;
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
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() );
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 );
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() );
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 ) );
std::string strId(to_string(mActiveMatGroup));
stdMatName += "id";
stdMatName += strId;
stdMatName += "_";
if ( nullptr != name ) {
stdMatName += std::string( name );
if (nullptr != name) {
stdMatName += std::string(name);
} else {
stdMatName += "basemat";
}
matName.Set( stdMatName );
matName.Set(stdMatName);
mat = new aiMaterial;
mat->AddProperty( &matName, AI_MATKEY_NAME );
mat->AddProperty(&matName, AI_MATKEY_NAME);
assignDiffuseColor( mat );
assignDiffuseColor(mat);
}
return mat;
}
private:
bool ReadToStartElement(const std::string& startTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
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) {
@ -390,9 +388,9 @@ private:
return false;
}
bool ReadToEndElement(const std::string& closeTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
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) {
@ -410,11 +408,11 @@ private:
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::vector<aiMesh*> mMeshes;
std::vector<aiMesh *> mMeshes;
MatArray mMatArray;
unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray;
XmlReader* xmlReader;
XmlReader *xmlReader;
};
} //namespace D3MF
@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
"3mf"
};
D3MFImporter::D3MFImporter()
: BaseImporter() {
D3MFImporter::D3MFImporter() :
BaseImporter() {
// empty
}
@ -442,17 +440,17 @@ D3MFImporter::~D3MFImporter() {
}
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension( GetExtension( filename ) );
if(extension == desc.mFileExtensions ) {
const std::string extension(GetExtension(filename));
if (extension == desc.mFileExtensions) {
return true;
} else if ( !extension.length() || checkSig ) {
if ( nullptr == pIOHandler ) {
} else if (!extension.length() || checkSig) {
if (nullptr == pIOHandler) {
return false;
}
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false;
}
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
return opcPackage.validate();
}
@ -467,7 +465,7 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
return &desc;
}
void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));

View File

@ -45,19 +45,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFOpcPackage.h"
#include <assimp/Exceptional.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <cstdlib>
#include <memory>
#include <vector>
#include <map>
#include "3MFXmlTags.h"
#include <algorithm>
#include <cassert>
#include "3MFXmlTags.h"
#include <cstdlib>
#include <map>
#include <memory>
#include <vector>
namespace Assimp {
@ -68,49 +68,45 @@ typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
class OpcPackageRelationshipReader {
public:
OpcPackageRelationshipReader(XmlReader* xmlReader) {
while(xmlReader->read()) {
if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER)
{
OpcPackageRelationshipReader(XmlReader *xmlReader) {
while (xmlReader->read()) {
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) {
ParseRootNode(xmlReader);
}
}
}
void ParseRootNode(XmlReader* xmlReader)
{
void ParseRootNode(XmlReader *xmlReader) {
ParseAttributes(xmlReader);
while(xmlReader->read())
{
if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE)
{
while (xmlReader->read()) {
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
ParseChildNode(xmlReader);
}
}
}
void ParseAttributes(XmlReader*) {
void ParseAttributes(XmlReader *) {
// empty
}
bool validateRels( OpcPackageRelationshipPtr &relPtr ) {
if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) {
bool validateRels(OpcPackageRelationshipPtr &relPtr) {
if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) {
return false;
}
return true;
}
void ParseChildNode(XmlReader* xmlReader) {
void ParseChildNode(XmlReader *xmlReader) {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str());
relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str());
relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str());
if ( validateRels( relPtr ) ) {
m_relationShips.push_back( relPtr );
if (validateRels(relPtr)) {
m_relationShips.push_back(relPtr);
}
}
@ -118,51 +114,52 @@ public:
};
// ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr)
, mZipArchive() {
mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
if(!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile+ ".");
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr), mZipArchive() {
mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile + ".");
}
std::vector<std::string> fileList;
mZipArchive->getFileList(fileList);
for (auto& file: fileList) {
if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
//PkgRelationshipReader pkgRelReader(file, archive);
ai_assert(mZipArchive->Exists(file.c_str()));
for (auto &file : fileList) {
if (file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
if (!mZipArchive->Exists(file.c_str())) {
continue;
}
IOStream *fileStream = mZipArchive->Open(file.c_str());
ai_assert(fileStream != nullptr);
if (nullptr == fileStream) {
ai_assert(fileStream != nullptr);
continue;
}
std::string rootFile = ReadPackageRootRelationship(fileStream);
if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
rootFile = rootFile.substr( 1 );
if ( rootFile[ 0 ] == '/' ) {
if (rootFile.size() > 0 && rootFile[0] == '/') {
rootFile = rootFile.substr(1);
if (rootFile[0] == '/') {
// deal with zip-bug
rootFile = rootFile.substr( 1 );
rootFile = rootFile.substr(1);
}
}
ASSIMP_LOG_DEBUG(rootFile);
ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
mZipArchive->Close(fileStream);
mRootStream = mZipArchive->Open(rootFile.c_str());
ai_assert( mRootStream != nullptr );
if ( nullptr == mRootStream ) {
throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
ai_assert(mRootStream != nullptr);
if (nullptr == mRootStream) {
throw DeadlyExportError("Cannot open root-file in archive : " + rootFile);
}
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
} else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file);
} else {
ASSIMP_LOG_WARN_F("Ignored file of unknown type: ",file);
ASSIMP_LOG_WARN_F("Ignored file of unknown type: ", file);
}
}
}
@ -170,32 +167,32 @@ D3MFOpcPackage::~D3MFOpcPackage() {
mZipArchive->Close(mRootStream);
}
IOStream* D3MFOpcPackage::RootStream() const {
IOStream *D3MFOpcPackage::RootStream() const {
return mRootStream;
}
static const std::string ModelRef = "3D/3dmodel.model";
bool D3MFOpcPackage::validate() {
if ( nullptr == mRootStream || nullptr == mZipArchive ) {
if (nullptr == mRootStream || nullptr == mZipArchive) {
return false;
}
return mZipArchive->Exists( ModelRef.c_str() );
return mZipArchive->Exists(ModelRef.c_str());
}
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
OpcPackageRelationshipReader reader(xml.get());
auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.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;
});
if ( itr == reader.m_relationShips.end() ) {
throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE );
if (itr == reader.m_relationShips.end()) {
throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
}
return (*itr)->target;

View File

@ -192,7 +192,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
objects.push_back(Object());
Object &obj = objects.back();
aiLight *light = NULL;
aiLight *light = nullptr;
if (!ASSIMP_strincmp(buffer, "light", 5)) {
// This is a light source. Add it to the list
mLights->push_back(light = new aiLight());
@ -207,7 +207,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
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);
ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
obj.type = Object::Light;
} else if (!ASSIMP_strincmp(buffer, "group", 5)) {
obj.type = Object::Group;
@ -294,7 +294,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
// example writes no surf chunks
if (!Q3DWorkAround) {
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
}
--buffer; // make sure the line is processed a second time
// break; --- see fix notes above
@ -472,29 +472,29 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
}
switch ((*it).flags & 0xf) {
// closed line
case 0x1:
needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
break;
// closed line
case 0x1:
needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
break;
// unclosed line
case 0x2:
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
break;
// unclosed line
case 0x2:
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
break;
// 0 == polygon, else unknown
default:
if ((*it).flags & 0xf) {
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(0xf);
}
// 0 == polygon, else unknown
default:
if ((*it).flags & 0xf) {
ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(0xf);
}
// the number of faces increments by one, the number
// of vertices by surface.numref.
needMat[idx].first++;
needMat[idx].second += (unsigned int)(*it).entries.size();
// the number of faces increments by one, the number
// of vertices by surface.numref.
needMat[idx].first++;
needMat[idx].second += (unsigned int)(*it).entries.size();
};
}
unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes];
@ -535,7 +535,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
// allocate UV coordinates, but only if the texture name for the
// surface is not empty
aiVector3D *uv = NULL;
aiVector3D *uv = nullptr;
if (object.texture.length()) {
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2;
@ -627,7 +627,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name);
std::vector<aiMesh *> cpy(meshes.size() - oldm, NULL);
std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
@ -644,20 +644,20 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
else {
// generate a name depending on the type of the node
switch (object.type) {
case Object::Group:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
break;
case Object::Poly:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
break;
case Object::Light:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
break;
case Object::Group:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
break;
case Object::Poly:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
break;
case Object::Light:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
break;
// there shouldn't be more than one world, but we don't care
case Object::World:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
break;
// there shouldn't be more than one world, but we don't care
case Object::World:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
break;
}
}
@ -696,7 +696,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file
if ( file.get() == nullptr ) {
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open AC3D file " + pFile + ".");
}

View File

@ -56,27 +56,20 @@ struct aiMesh;
struct aiMaterial;
struct aiLight;
namespace Assimp {
namespace Assimp {
// ---------------------------------------------------------------------------
/** AC3D (*.ac) importer class
*/
class AC3DImporter : public BaseImporter
{
class AC3DImporter : public BaseImporter {
public:
AC3DImporter();
~AC3DImporter();
// Represents an AC3D material
struct Material
{
Material()
: rgb (0.6f,0.6f,0.6f)
, spec (1.f,1.f,1.f)
, shin (0.f)
, trans (0.f)
{}
struct Material {
Material() :
rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {}
// base color of the material
aiColor3D rgb;
@ -101,43 +94,25 @@ public:
};
// Represents an AC3D surface
struct Surface
{
Surface()
: mat (0)
, flags (0)
{}
struct Surface {
Surface() :
mat(0), flags(0) {}
unsigned int mat,flags;
unsigned int mat, flags;
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
std::vector< SurfaceEntry > entries;
typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
std::vector<SurfaceEntry> entries;
};
// Represents an AC3D object
struct Object
{
Object()
: type (World)
, name( "" )
, children()
, texture( "" )
, texRepeat( 1.f, 1.f )
, texOffset( 0.0f, 0.0f )
, rotation()
, translation()
, vertices()
, surfaces()
, numRefs (0)
, subDiv (0)
, crease()
{}
struct Object {
Object() :
type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {}
// Type description
enum Type
{
enum Type {
World = 0x0,
Poly = 0x1,
Poly = 0x1,
Group = 0x2,
Light = 0x4
} type;
@ -177,37 +152,33 @@ public:
float crease;
};
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const;
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details */
const aiImporterDesc* GetInfo () const;
const aiImporterDesc *GetInfo() const;
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler);
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.*/
void SetupProperties(const Importer* pImp);
void SetupProperties(const Importer *pImp);
private:
// -------------------------------------------------------------------
/** Get the next line from the file.
* @return false if the end of the file was reached*/
@ -218,7 +189,7 @@ private:
* load subobjects, the method returns after a 'kids 0' was
* encountered.
* @objects List of output objects*/
void LoadObjectSection(std::vector<Object>& objects);
void LoadObjectSection(std::vector<Object> &objects);
// -------------------------------------------------------------------
/** Convert all objects into meshes and nodes.
@ -227,24 +198,24 @@ private:
* @param outMaterials List of output materials
* @param materials Material list
* @param Scenegraph node for the object */
aiNode* ConvertObjectSection(Object& object,
std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*>& outMaterials,
const std::vector<Material>& materials,
aiNode* parent = NULL);
aiNode *ConvertObjectSection(Object &object,
std::vector<aiMesh *> &meshes,
std::vector<aiMaterial *> &outMaterials,
const std::vector<Material> &materials,
aiNode *parent = nullptr);
// -------------------------------------------------------------------
/** Convert a material
* @param object Current object
* @param matSrc Source material description
* @param matDest Destination material to be filled */
void ConvertMaterial(const Object& object,
const Material& matSrc,
aiMaterial& matDest);
void ConvertMaterial(const Object &object,
const Material &matSrc,
aiMaterial &matDest);
private:
// points to the next data line
const char* buffer;
const char *buffer;
// Configuration option: if enabled, up to two meshes
// are generated per material: those faces who have
@ -261,7 +232,7 @@ private:
unsigned int mNumMeshes;
// current list of light sources
std::vector<aiLight*>* mLights;
std::vector<aiLight *> *mLights;
// name counters
unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter;

View File

@ -0,0 +1,674 @@
/*
---------------------------------------------------------------------------
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/DefaultIOSystem.h>
#include <assimp/fast_atof.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

@ -1,4 +1,4 @@
/*
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/*
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/*
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/*
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------

View File

@ -0,0 +1,872 @@
/*
---------------------------------------------------------------------------
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_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
#include "AMFImporter.hpp"
// Header files, Assimp.
#include <assimp/SceneCombiner.h>
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
// Header files, stdlib.
#include <iterator>
namespace Assimp {
aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const {
aiColor4D tcol;
// Check if stored data are supported.
if (!Composition.empty()) {
throw DeadlyImportError("IME. GetColor for composition");
} else if (Color->Composed) {
throw DeadlyImportError("IME. GetColor, composed color");
} else {
tcol = Color->Color;
}
// Check if default color must be used
if ((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) {
tcol.r = 0.5f;
tcol.g = 0.5f;
tcol.b = 0.5f;
tcol.a = 1;
}
return tcol;
}
void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray) const {
CAMFImporter_NodeElement_Vertices *vn = nullptr;
size_t col_idx;
// All data stored in "vertices", search for it.
for (CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices *)ne_child;
}
// If "vertices" not found then no work for us.
if (vn == nullptr) return;
pVertexCoordinateArray.reserve(vn->Child.size()); // all coordinates stored as child and we need to reserve space for future push_back's.
pVertexColorArray.resize(vn->Child.size()); // colors count equal vertices count.
col_idx = 0;
// Inside vertices collect all data and place to arrays
for (CAMFImporter_NodeElement *vn_child : vn->Child) {
// vertices, colors
if (vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) {
// by default clear color for current vertex
pVertexColorArray[col_idx] = nullptr;
for (CAMFImporter_NodeElement *vtx : vn_child->Child) {
if (vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates) {
pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates *)vtx)->Coordinate);
continue;
}
if (vtx->Type == CAMFImporter_NodeElement::ENET_Color) {
pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color *)vtx;
continue;
}
} // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
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 &pID_R, const std::string &pID_G, const std::string &pID_B,
const std::string &pID_A) {
size_t TextureConverted_Index;
std::string TextureConverted_ID;
// check input data
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) {
if (tex_convd.ID == TextureConverted_ID) {
return TextureConverted_Index;
} else {
++TextureConverted_Index;
}
}
//
// Converted texture not found, create it.
//
CAMFImporter_NodeElement_Texture *src_texture[4]{ nullptr };
std::vector<CAMFImporter_NodeElement_Texture *> src_texture_4check;
SPP_Texture converted_texture;
{ // find all specified source textures
CAMFImporter_NodeElement *t_tex;
// R
if (!pID_R.empty()) {
if (!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
src_texture[0] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else {
src_texture[0] = nullptr;
}
// G
if (!pID_G.empty()) {
if (!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
src_texture[1] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else {
src_texture[1] = nullptr;
}
// B
if (!pID_B.empty()) {
if (!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
src_texture[2] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else {
src_texture[2] = nullptr;
}
// A
if (!pID_A.empty()) {
if (!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
src_texture[3] = (CAMFImporter_NodeElement_Texture *)t_tex;
src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
} else {
src_texture[3] = nullptr;
}
} // END: find all specified source textures
// check that all textures has same size
if (src_texture_4check.size() > 1) {
for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++) {
if ((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth)) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
}
}
} // if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture.Width = src_texture_4check[0]->Width;
converted_texture.Height = src_texture_4check[0]->Height;
converted_texture.Depth = src_texture_4check[0]->Depth;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture.Tiled = false;
for (uint8_t i = 0; i < src_texture_4check.size(); i++)
converted_texture.Tiled |= src_texture_4check[i]->Tiled;
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
if (!pID_R.empty()) converted_texture.FormatHint[4] = '8';
if (!pID_G.empty()) converted_texture.FormatHint[5] = '8';
if (!pID_B.empty()) converted_texture.FormatHint[6] = '8';
if (!pID_A.empty()) converted_texture.FormatHint[7] = '8';
//
// Сopy data of textures.
//
size_t tex_size = 0;
size_t step = 0;
size_t off_g = 0;
size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied.
if (!pID_R.empty() && nullptr != src_texture[0]) {
tex_size += src_texture[0]->Data.size();
step++, off_g++, off_b++;
}
if (!pID_G.empty() && nullptr != src_texture[1]) {
tex_size += src_texture[1]->Data.size();
step++, off_b++;
}
if (!pID_B.empty() && nullptr != src_texture[2]) {
tex_size += src_texture[2]->Data.size();
step++;
}
if (!pID_A.empty() && nullptr != src_texture[3]) {
tex_size += src_texture[3]->Data.size();
step++;
}
// Create target array.
converted_texture.Data = new uint8_t[tex_size];
// And copy data
auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
if (!pID.empty()) {
for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
CAMFImporter_NodeElement_Texture *tex = src_texture[pSrcTexNum];
ai_assert(tex);
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
CopyTextureData(pID_R, 0, step, 0);
CopyTextureData(pID_G, off_g, step, 1);
CopyTextureData(pID_B, off_b, step, 2);
CopyTextureData(pID_A, step - 1, step, 3);
// Store new converted texture ID
converted_texture.ID = TextureConverted_ID;
// Store new converted texture
mTexture_Converted.push_back(converted_texture);
return TextureConverted_Index;
}
void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) {
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) return false;
if (pTexMap2 == nullptr) return false;
if (pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
if (pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
if (pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
if (pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
return true;
};
pOutputList_Separated.clear();
if (pInputList.empty()) return;
do {
SComplexFace face_start = pInputList.front();
std::list<SComplexFace> face_list_cur;
for (std::list<SComplexFace>::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;) {
if (texmap_is_equal(face_start.TexMap, it->TexMap)) {
auto it_old = it;
++it;
face_list_cur.push_back(*it_old);
pInputList.erase(it_old);
} else {
++it;
}
}
if (!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
} while (!pInputList.empty());
}
void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata *> &metadataList, aiNode &sceneNode) const {
if (!metadataList.empty()) {
if (sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
// copy collected metadata to output node.
sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size()));
size_t meta_idx(0);
for (const CAMFImporter_NodeElement_Metadata &metadata : metadataList) {
sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
}
} // if(!metadataList.empty())
}
void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object &pNodeElement, std::list<aiMesh *> &pMeshList, aiNode **pSceneNode) {
CAMFImporter_NodeElement_Color *object_color = nullptr;
// create new aiNode and set name as <object> has.
*pSceneNode = new aiNode;
(*pSceneNode)->mName = pNodeElement.ID;
// read mesh and color
for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
std::vector<aiVector3D> vertex_arr;
std::vector<CAMFImporter_NodeElement_Color *> color_arr;
// color for object
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color *)ne_child;
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) {
// Create arrays from children of mesh: vertices.
PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr);
// Use this arrays as a source when creating every aiMesh
Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
}
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
}
void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
const std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray,
const CAMFImporter_NodeElement_Color *pObjectColor, std::list<aiMesh *> &pMeshList, aiNode &pSceneNode) {
std::list<unsigned int> mesh_idx;
// all data stored in "volume", search for it.
for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
const CAMFImporter_NodeElement_Color *ne_volume_color = nullptr;
const SPP_Material *cur_mat = nullptr;
if (ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) {
/******************* Get faces *******************/
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<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh.
// check if volume use material
if (!ne_volume->MaterialID.empty()) {
if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID);
}
// inside "volume" collect all data and place to arrays or create new objects
for (const CAMFImporter_NodeElement *ne_volume_child : ne_volume->Child) {
// color for volume
if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color) {
ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_volume_child);
} else if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle) // triangles, triangles colors
{
const CAMFImporter_NodeElement_Triangle &tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle *>(ne_volume_child);
SComplexFace complex_face;
// initialize pointers
complex_face.Color = nullptr;
complex_face.TexMap = nullptr;
// get data from triangle children: color, texture coordinates.
if (tri_al.Child.size()) {
for (const CAMFImporter_NodeElement *ne_triangle_child : tri_al.Child) {
if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color)
complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_triangle_child);
else if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap)
complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap *>(ne_triangle_child);
}
} // if(tri_al.Child.size())
// create new face and store it.
complex_face.Face.mNumIndices = 3;
complex_face.Face.mIndices = new unsigned int[3];
complex_face.Face.mIndices[0] = static_cast<unsigned int>(tri_al.V[0]);
complex_face.Face.mIndices[1] = static_cast<unsigned int>(tri_al.V[1]);
complex_face.Face.mIndices[2] = static_cast<unsigned int>(tri_al.V[2]);
complex_faces_list.push_back(complex_face);
}
} // for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
/**** Split faces list: one list per mesh ****/
PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist);
/***** Create mesh for every faces list ******/
for (std::list<SComplexFace> &face_list_cur : complex_faces_toplist) {
auto VertexIndex_GetMinimal = [](const std::list<SComplexFace> &pFaceList, const size_t *pBiggerThan) -> size_t {
size_t rv = 0;
if (pBiggerThan != nullptr) {
bool found = false;
for (const SComplexFace &face : pFaceList) {
for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) {
if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
rv = face.Face.mIndices[idx_vert];
found = true;
break;
}
}
if (found) break;
}
if (!found) return *pBiggerThan;
} else {
rv = pFaceList.front().Face.mIndices[0];
} // if(pBiggerThan != nullptr) else
for (const SComplexFace &face : pFaceList) {
for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) {
if (face.Face.mIndices[vi] < rv) {
if (pBiggerThan != nullptr) {
if (face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
} else {
rv = face.Face.mIndices[vi];
}
}
}
} // for(const SComplexFace& face: pFaceList)
return rv;
}; // auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
auto VertexIndex_Replace = [](std::list<SComplexFace> &pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void {
for (const SComplexFace &face : pFaceList) {
for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) {
if (face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast<unsigned int>(pIdx_To);
}
}
}; // auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D {
// Color priorities(In descending order):
// 1. triangle color;
// 2. vertex color;
// 3. volume color;
// 4. object color;
// 5. material;
// 6. default - invisible coat.
//
// Fill vertices colors in color priority list above that's points from 1 to 6.
if ((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr)) // check for vertex color
{
if (pVertexColorArray[pIdx]->Composed)
throw DeadlyImportError("IME: vertex color composed");
else
return pVertexColorArray[pIdx]->Color;
} else if (ne_volume_color != nullptr) // check for volume color
{
if (ne_volume_color->Composed)
throw DeadlyImportError("IME: volume color composed");
else
return ne_volume_color->Color;
} else if (pObjectColor != nullptr) // check for object color
{
if (pObjectColor->Composed)
throw DeadlyImportError("IME: object color composed");
else
return pObjectColor->Color;
} else if (cur_mat != nullptr) // check for material
{
return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z);
} else // set default color.
{
return { 0, 0, 0, 0 };
} // if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else
}; // auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
aiMesh *tmesh = new aiMesh;
tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // Only triangles is supported by AMF.
//
// set geometry and colors (vertices)
//
// copy faces/triangles
tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
tmesh->mFaces = new aiFace[tmesh->mNumFaces];
// 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.
// 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.
std::vector<aiVector3D> vert_arr, texcoord_arr;
std::vector<aiColor4D> col_arr;
vert_arr.reserve(VertexCount_Max * 2); // "* 2" - see below TODO.
col_arr.reserve(VertexCount_Max * 2);
{ // fill arrays
size_t vert_idx_from, vert_idx_to;
// first iteration.
vert_idx_to = 0;
vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr);
vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
// rest iterations
do {
vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to);
if (vert_idx_from == vert_idx_to) break; // all indices are transferred,
vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
vert_idx_to++;
if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
} while (true);
} // fill arrays. END.
//
// check if triangle colors are used and create additional faces if needed.
//
for (const SComplexFace &face_cur : face_list_cur) {
if (face_cur.Color != nullptr) {
aiColor4D face_color;
size_t vert_idx_new = vert_arr.size();
if (face_cur.Color->Composed)
throw DeadlyImportError("IME: face color composed");
else
face_color = face_cur.Color->Color;
for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) {
vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind]));
col_arr.push_back(face_color);
face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(vert_idx_new++);
}
} // if(face_cur.Color != nullptr)
} // for(const SComplexFace& face_cur: face_list_cur)
//
// if texture is used then copy texture coordinates too.
//
if (face_list_cur.front().TexMap != nullptr) {
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
/// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
/// optimisation.
bool *idx_vert_used;
idx_vert_used = new bool[VertexCount_Max * 2];
for (size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++)
idx_vert_used[i] = false;
// This ID's will be used when set materials ID in scene.
tmesh->mMaterialIndex = static_cast<unsigned int>(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R,
face_list_cur.front().TexMap->TextureID_G,
face_list_cur.front().TexMap->TextureID_B,
face_list_cur.front().TexMap->TextureID_A));
texcoord_arr.resize(VertexCount_Max * 2);
for (const SComplexFace &face_cur : face_list_cur) {
for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) {
const size_t idx_vert = face_cur.Face.mIndices[idx_ind];
if (!idx_vert_used[idx_vert]) {
texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind];
idx_vert_used[idx_vert] = true;
} else if (texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind]) {
// in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture
// coordinates.
vert_arr.push_back(vert_arr.at(idx_vert));
col_arr.push_back(col_arr.at(idx_vert));
texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind];
face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(idx_vert_new++);
}
} // for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
} // for(const SComplexFace& face_cur: face_list_cur)
delete[] idx_vert_used;
// shrink array
texcoord_arr.resize(idx_vert_new);
} // if(face_list_cur.front().TexMap != nullptr)
//
// copy collected data to mesh
//
tmesh->mNumVertices = static_cast<unsigned int>(vert_arr.size());
tmesh->mVertices = new aiVector3D[tmesh->mNumVertices];
tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices];
memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D));
if (texcoord_arr.size() > 0) {
tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices];
memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
tmesh->mNumUVComponents[0] = 2; // U and V stored in "x", "y" of aiVector3D.
}
size_t idx_face = 0;
for (const SComplexFace &face_cur : face_list_cur)
tmesh->mFaces[idx_face++] = face_cur.Face;
// store new aiMesh
mesh_idx.push_back(static_cast<unsigned int>(pMeshList.size()));
pMeshList.push_back(tmesh);
} // for(const std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
} // if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
// if meshes was created then assign new indices with current aiNode
if (!mesh_idx.empty()) {
std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
pSceneNode.mNumMeshes = static_cast<unsigned int>(mesh_idx.size());
pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
for (size_t i = 0; i < pSceneNode.mNumMeshes; i++)
pSceneNode.mMeshes[i] = *mit++;
} // if(mesh_idx.size() > 0)
}
void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material &pMaterial) {
SPP_Material new_mat;
new_mat.ID = pMaterial.ID;
for (const CAMFImporter_NodeElement *mat_child : pMaterial.Child) {
if (mat_child->Type == CAMFImporter_NodeElement::ENET_Color) {
new_mat.Color = (CAMFImporter_NodeElement_Color *)mat_child;
} else if (mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata) {
new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata *)mat_child);
}
} // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
// place converted material to special list
mMaterial_Converted.push_back(new_mat);
}
void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation &pConstellation, std::list<aiNode *> &pNodeList) const {
aiNode *con_node;
std::list<aiNode *> ch_node;
// We will build next hierarchy:
// aiNode as parent (<constellation>) for set of nodes as a children
// |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
// ...
// \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
con_node = new aiNode;
con_node->mName = pConstellation.ID;
// Walk through children and search for instances of another objects, constellations.
for (const CAMFImporter_NodeElement *ne : pConstellation.Child) {
aiMatrix4x4 tmat;
aiNode *t_node;
aiNode *found_node;
if (ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue;
if (ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
// create alias for conveniance
CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne);
// find referenced object
if (!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for applying transformation
t_node = new aiNode;
t_node->mParent = con_node;
// apply transformation
aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
// create array for one child node
t_node->mNumChildren = 1;
t_node->mChildren = new aiNode *[t_node->mNumChildren];
SceneCombiner::Copy(&t_node->mChildren[0], found_node);
t_node->mChildren[0]->mParent = t_node;
ch_node.push_back(t_node);
} // for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
// copy found aiNode's as children
if (ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
size_t ch_idx = 0;
con_node->mNumChildren = static_cast<unsigned int>(ch_node.size());
con_node->mChildren = new aiNode *[con_node->mNumChildren];
for (aiNode *node : ch_node)
con_node->mChildren[ch_idx++] = node;
// and place "root" of <constellation> node to node list
pNodeList.push_back(con_node);
}
void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
std::list<aiNode *> node_list;
std::list<aiMesh *> mesh_list;
std::list<CAMFImporter_NodeElement_Metadata *> meta_list;
//
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
// For building aiScene we are must to do few steps:
// at first creating root node for aiScene.
pScene->mRootNode = new aiNode;
pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
// search for root(<amf>) element
CAMFImporter_NodeElement *root_el = nullptr;
for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
if (ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
root_el = ne;
break;
} // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
// Check if root element are found.
if (root_el == nullptr) 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>,
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
// at any moment.
//
// 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
if (root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material *)root_child));
}
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
//
// 3. <object>
for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
if (root_child->Type == CAMFImporter_NodeElement::ENET_Object) {
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>
Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object *)root_child), mesh_list, &tnode);
if (tnode != nullptr) node_list.push_back(tnode);
}
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
// And finally read rest of nodes.
//
for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
// 4. <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.
Postprocess_BuildConstellation(*((CAMFImporter_NodeElement_Constellation *)root_child), node_list);
}
// 5, <metadata>
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)
// at now we can add collected metadata to root node
Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
//
// Check constellation children
//
// As said in specification:
// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
// And at this step we are checking that relations.
nl_clean_loop:
if (node_list.size() > 1) {
// walk through all nodes
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.
std::list<aiNode *>::const_iterator next_it = nl_it;
++next_it;
for (; next_it != node_list.end(); ++next_it) {
if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
node_list.erase(nl_it);
goto nl_clean_loop;
}
} // for(; next_it != node_list.end(); next_it++)
} // for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
}
//
// move created objects to aiScene
//
//
// Nodes
if (!node_list.empty()) {
std::list<aiNode *>::const_iterator nl_it = node_list.begin();
pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
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
// mRootNode only as parent.
(*nl_it)->mParent = pScene->mRootNode;
pScene->mRootNode->mChildren[i] = *nl_it++;
}
} // if(node_list.size() > 0)
//
// Meshes
if (!mesh_list.empty()) {
std::list<aiMesh *>::const_iterator ml_it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (size_t i = 0; i < pScene->mNumMeshes; i++)
pScene->mMeshes[i] = *ml_it++;
} // if(mesh_list.size() > 0)
//
// Textures
pScene->mNumTextures = static_cast<unsigned int>(mTexture_Converted.size());
if (pScene->mNumTextures > 0) {
size_t idx;
idx = 0;
pScene->mTextures = new aiTexture *[pScene->mNumTextures];
for (const SPP_Texture &tex_convd : mTexture_Converted) {
pScene->mTextures[idx] = new aiTexture;
pScene->mTextures[idx]->mWidth = static_cast<unsigned int>(tex_convd.Width);
pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data;
// texture format description.
strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
idx++;
} // for(const SPP_Texture& tex_convd: mTexture_Converted)
// Create materials for embedded textures.
idx = 0;
pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size());
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
for (const SPP_Texture &tex_convd : mTexture_Converted) {
const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx));
const int mode = aiTextureOp_Multiply;
const int repeat = tex_convd.Tiled ? 1 : 0;
pScene->mMaterials[idx] = new aiMaterial;
pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
idx++;
}
} // if(pScene->mNumTextures > 0)
} // END: after that walk through children of root and collect data
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -40,15 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Defines the helper data structures for importing ASE files */
#ifndef AI_ASEFILEHELPER_H_INC
#define AI_ASEFILEHELPER_H_INC
// public ASSIMP headers
#include <assimp/types.h>
#include <assimp/mesh.h>
#include <assimp/anim.h>
#include <assimp/mesh.h>
#include <assimp/types.h>
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
@ -57,29 +56,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/qnan.h>
// ASE is quite similar to 3ds. We can reuse some structures
#include "3DS/3DSLoader.h"
#include "AssetLib/3DS/3DSLoader.h"
namespace Assimp {
namespace ASE {
namespace Assimp {
namespace ASE {
using namespace D3DS;
// ---------------------------------------------------------------------------
/** Helper structure representing an ASE material */
struct Material : public D3DS::Material
{
struct Material : public D3DS::Material {
//! Default constructor has been deleted
Material() = delete;
//! Constructor with explicit name
explicit Material(const std::string &name)
: D3DS::Material(name)
, pcInstance(NULL)
, bNeed (false) {
explicit Material(const std::string &name) :
D3DS::Material(name),
pcInstance(nullptr),
bNeed(false) {
// empty
}
Material(const Material &other) = default;
Material(const Material &other) = default;
Material &operator=(const Material &other) {
if (this == &other) {
@ -93,19 +91,16 @@ struct Material : public D3DS::Material
return *this;
}
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
Material(Material &&other) AI_NO_EXCEPT
: D3DS::Material(std::move(other))
, avSubMaterials(std::move(other.avSubMaterials))
, pcInstance(std::move(other.pcInstance))
, bNeed(std::move(other.bNeed))
{
: D3DS::Material(std::move(other)),
avSubMaterials(std::move(other.avSubMaterials)),
pcInstance(std::move(other.pcInstance)),
bNeed(std::move(other.bNeed)) {
other.pcInstance = nullptr;
}
Material &operator=( Material &&other) AI_NO_EXCEPT {
Material &operator=(Material &&other) AI_NO_EXCEPT {
if (this == &other) {
return *this;
}
@ -121,15 +116,13 @@ struct Material : public D3DS::Material
return *this;
}
~Material() {}
//! Contains all sub materials of this material
std::vector<Material> avSubMaterials;
//! aiMaterial object
aiMaterial* pcInstance;
aiMaterial *pcInstance;
//! Can we remove this material?
bool bNeed;
@ -140,8 +133,8 @@ struct Material : public D3DS::Material
struct Face : public FaceWithSmoothingGroup {
//! Default constructor. Initializes everything with 0
Face() AI_NO_EXCEPT
: iMaterial(DEFAULT_MATINDEX)
, iFace(0) {
: iMaterial(DEFAULT_MATINDEX),
iFace(0) {
// empty
}
@ -172,8 +165,8 @@ struct Bone {
Bone() = delete;
//! Construction from an existing name
explicit Bone( const std::string& name)
: mName(name) {
explicit Bone(const std::string &name) :
mName(name) {
// empty
}
@ -186,33 +179,34 @@ struct Bone {
struct BoneVertex {
//! Bone and corresponding vertex weight.
//! -1 for unrequired bones ....
std::vector<std::pair<int,float> > mBoneWeights;
std::vector<std::pair<int, float>> mBoneWeights;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file animation */
struct Animation {
enum Type {
TRACK = 0x0,
BEZIER = 0x1,
TCB = 0x2
} mRotationType, mScalingType, mPositionType;
TRACK = 0x0,
BEZIER = 0x1,
TCB = 0x2
} mRotationType,
mScalingType, mPositionType;
Animation() AI_NO_EXCEPT
: mRotationType (TRACK)
, mScalingType (TRACK)
, mPositionType (TRACK) {
: mRotationType(TRACK),
mScalingType(TRACK),
mPositionType(TRACK) {
// empty
}
//! List of track rotation keyframes
std::vector< aiQuatKey > akeyRotations;
std::vector<aiQuatKey> akeyRotations;
//! List of track position keyframes
std::vector< aiVectorKey > akeyPositions;
std::vector<aiVectorKey> akeyPositions;
//! List of track scaling keyframes
std::vector< aiVectorKey > akeyScaling;
std::vector<aiVectorKey> akeyScaling;
};
// ---------------------------------------------------------------------------
@ -220,7 +214,7 @@ struct Animation {
struct InheritanceInfo {
//! Default constructor
InheritanceInfo() AI_NO_EXCEPT {
for ( size_t i=0; i<3; ++i ) {
for (size_t i = 0; i < 3; ++i) {
abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
}
}
@ -239,17 +233,15 @@ struct InheritanceInfo {
/** Represents an ASE file node. Base class for mesh, light and cameras */
struct BaseNode {
enum Type {
Light,
Camera,
Mesh,
Light,
Camera,
Mesh,
Dummy
} mType;
//! Construction from an existing name
BaseNode(Type _mType, const std::string &name)
: mType (_mType)
, mName (name)
, mProcessed (false) {
BaseNode(Type _mType, const std::string &name) :
mType(_mType), mName(name), mProcessed(false) {
// Set mTargetPosition to qnan
const ai_real qnan = get_qnan();
mTargetPosition.x = qnan;
@ -289,14 +281,9 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
Mesh() = delete;
//! Construction from an existing name
explicit Mesh(const std::string &name)
: BaseNode( BaseNode::Mesh, name )
, mVertexColors()
, mBoneVertices()
, mBones()
, iMaterialIndex(Face::DEFAULT_MATINDEX)
, bSkip (false) {
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
explicit Mesh(const std::string &name) :
BaseNode(BaseNode::Mesh, name), mVertexColors(), mBoneVertices(), mBones(), iMaterialIndex(Face::DEFAULT_MATINDEX), bSkip(false) {
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
this->mNumUVComponents[c] = 2;
}
}
@ -325,10 +312,8 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE light source */
struct Light : public BaseNode
{
enum LightType
{
struct Light : public BaseNode {
enum LightType {
OMNI,
TARGET,
FREE,
@ -339,17 +324,13 @@ struct Light : public BaseNode
Light() = delete;
//! Construction from an existing name
explicit Light(const std::string &name)
: BaseNode (BaseNode::Light, name)
, mLightType (OMNI)
, mColor (1.f,1.f,1.f)
, mIntensity (1.f) // light is white by default
, mAngle (45.f)
, mFalloff (0.f)
{
explicit Light(const std::string &name) :
BaseNode(BaseNode::Light, name), mLightType(OMNI), mColor(1.f, 1.f, 1.f), mIntensity(1.f) // light is white by default
,
mAngle(45.f),
mFalloff(0.f) {
}
LightType mLightType;
aiColor3D mColor;
ai_real mIntensity;
@ -359,10 +340,8 @@ struct Light : public BaseNode
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE camera */
struct Camera : public BaseNode
{
enum CameraType
{
struct Camera : public BaseNode {
enum CameraType {
FREE,
TARGET
};
@ -370,18 +349,16 @@ struct Camera : public BaseNode
//! Default constructor has been deleted
Camera() = delete;
//! Construction from an existing name
explicit Camera(const std::string &name)
: BaseNode (BaseNode::Camera, name)
, mFOV (0.75f) // in radians
, mNear (0.1f)
, mFar (1000.f) // could be zero
, mCameraType (FREE)
{
explicit Camera(const std::string &name) :
BaseNode(BaseNode::Camera, name), mFOV(0.75f) // in radians
,
mNear(0.1f),
mFar(1000.f) // could be zero
,
mCameraType(FREE) {
}
ai_real mFOV, mNear, mFar;
CameraType mCameraType;
};
@ -391,7 +368,7 @@ struct Camera : public BaseNode
struct Dummy : public BaseNode {
//! Constructor
Dummy() AI_NO_EXCEPT
: BaseNode (BaseNode::Dummy, "DUMMY") {
: BaseNode(BaseNode::Dummy, "DUMMY") {
// empty
}
};
@ -414,7 +391,6 @@ private:
}
public:
// -------------------------------------------------------------------
//! Construct a parser from a given input file which is
//! guaranteed to be terminated with zero.
@ -422,15 +398,13 @@ public:
//! @param fileFormatDefault Assumed file format version. If the
//! file format is specified in the file the new value replaces
//! the default value.
Parser (const char* szFile, unsigned int fileFormatDefault);
Parser(const char *szFile, unsigned int fileFormatDefault);
// -------------------------------------------------------------------
//! Parses the file into the parsers internal representation
void Parse();
private:
// -------------------------------------------------------------------
//! Parse the *SCENE block in a file
void ParseLV1SceneBlock();
@ -446,45 +420,45 @@ private:
// -------------------------------------------------------------------
//! Parse a *<xxx>OBJECT block in a file
//! \param mesh Node to be filled
void ParseLV1ObjectBlock(BaseNode& mesh);
void ParseLV1ObjectBlock(BaseNode &mesh);
// -------------------------------------------------------------------
//! Parse a *MATERIAL blocks in a material list
//! \param mat Material structure to be filled
void ParseLV2MaterialBlock(Material& mat);
void ParseLV2MaterialBlock(Material &mat);
// -------------------------------------------------------------------
//! Parse a *NODE_TM block in a file
//! \param mesh Node (!) object to be filled
void ParseLV2NodeTransformBlock(BaseNode& mesh);
void ParseLV2NodeTransformBlock(BaseNode &mesh);
// -------------------------------------------------------------------
//! Parse a *TM_ANIMATION block in a file
//! \param mesh Mesh object to be filled
void ParseLV2AnimationBlock(BaseNode& mesh);
void ParseLV3PosAnimationBlock(ASE::Animation& anim);
void ParseLV3ScaleAnimationBlock(ASE::Animation& anim);
void ParseLV3RotAnimationBlock(ASE::Animation& anim);
void ParseLV2AnimationBlock(BaseNode &mesh);
void ParseLV3PosAnimationBlock(ASE::Animation &anim);
void ParseLV3ScaleAnimationBlock(ASE::Animation &anim);
void ParseLV3RotAnimationBlock(ASE::Animation &anim);
// -------------------------------------------------------------------
//! Parse a *MESH block in a file
//! \param mesh Mesh object to be filled
void ParseLV2MeshBlock(Mesh& mesh);
void ParseLV2MeshBlock(Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *LIGHT_SETTINGS block in a file
//! \param light Light object to be filled
void ParseLV2LightSettingsBlock(Light& light);
void ParseLV2LightSettingsBlock(Light &light);
// -------------------------------------------------------------------
//! Parse a *CAMERA_SETTINGS block in a file
//! \param cam Camera object to be filled
void ParseLV2CameraSettingsBlock(Camera& cam);
void ParseLV2CameraSettingsBlock(Camera &cam);
// -------------------------------------------------------------------
//! Parse the *MAP_XXXXXX blocks in a material
//! \param map Texture structure to be filled
void ParseLV3MapBlock(Texture& map);
void ParseLV3MapBlock(Texture &map);
// -------------------------------------------------------------------
//! Parse a *MESH_VERTEX_LIST block in a file
@ -493,7 +467,7 @@ private:
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshVertexListBlock(
unsigned int iNumVertices,Mesh& mesh);
unsigned int iNumVertices, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_FACE_LIST block in a file
@ -502,7 +476,7 @@ private:
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshFaceListBlock(
unsigned int iNumFaces,Mesh& mesh);
unsigned int iNumFaces, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_TVERT_LIST block in a file
@ -512,7 +486,7 @@ private:
//! \param mesh Mesh object to be filled
//! \param iChannel Output UVW channel
void ParseLV3MeshTListBlock(
unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0);
unsigned int iNumVertices, Mesh &mesh, unsigned int iChannel = 0);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACELIST block in a file
@ -522,7 +496,7 @@ private:
//! \param mesh Mesh object to be filled
//! \param iChannel Output UVW channel
void ParseLV3MeshTFaceListBlock(
unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0);
unsigned int iNumFaces, Mesh &mesh, unsigned int iChannel = 0);
// -------------------------------------------------------------------
//! Parse an additional mapping channel
@ -530,7 +504,7 @@ private:
//! \param iChannel Channel index to be filled
//! \param mesh Mesh object to be filled
void ParseLV3MappingChannel(
unsigned int iChannel, Mesh& mesh);
unsigned int iChannel, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_CVERTLIST block in a file
@ -539,7 +513,7 @@ private:
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshCListBlock(
unsigned int iNumVertices, Mesh& mesh);
unsigned int iNumVertices, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_CFACELIST block in a file
@ -548,70 +522,70 @@ private:
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshCFaceListBlock(
unsigned int iNumFaces, Mesh& mesh);
unsigned int iNumFaces, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_NORMALS block in a file
//! \param mesh Mesh object to be filled
void ParseLV3MeshNormalListBlock(Mesh& mesh);
void ParseLV3MeshNormalListBlock(Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_WEIGHTSblock in a file
//! \param mesh Mesh object to be filled
void ParseLV3MeshWeightsBlock(Mesh& mesh);
void ParseLV3MeshWeightsBlock(Mesh &mesh);
// -------------------------------------------------------------------
//! Parse the bone list of a file
//! \param mesh Mesh object to be filled
//! \param iNumBones Number of bones in the mesh
void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh);
void ParseLV4MeshBones(unsigned int iNumBones, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse the bone vertices list of a file
//! \param mesh Mesh object to be filled
//! \param iNumVertices Number of vertices to be parsed
void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh);
void ParseLV4MeshBonesVertices(unsigned int iNumVertices, Mesh &mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_FACE block in a file
//! \param out receive the face data
void ParseLV4MeshFace(ASE::Face& out);
void ParseLV4MeshFace(ASE::Face &out);
// -------------------------------------------------------------------
//! Parse a *MESH_VERT block in a file
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats)
//! \param rIndexOut Output index
void ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut);
void ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut);
// -------------------------------------------------------------------
//! Parse a *MESH_VERT block in a file
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats)
void ParseLV4MeshFloatTriple(ai_real* apOut);
void ParseLV4MeshFloatTriple(ai_real *apOut);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACE block in a file
//! (also works for MESH_CFACE)
//! \param apOut Output buffer (3 ints)
//! \param rIndexOut Output index
void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut);
void ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACE block in a file
//! (also works for MESH_CFACE)
//! \param apOut Output buffer (3 ints)
void ParseLV4MeshLongTriple(unsigned int* apOut);
void ParseLV4MeshLongTriple(unsigned int *apOut);
// -------------------------------------------------------------------
//! Parse a single float element
//! \param fOut Output float
void ParseLV4MeshFloat(ai_real& fOut);
void ParseLV4MeshFloat(ai_real &fOut);
// -------------------------------------------------------------------
//! Parse a single int element
//! \param iOut Output integer
void ParseLV4MeshLong(unsigned int& iOut);
void ParseLV4MeshLong(unsigned int &iOut);
// -------------------------------------------------------------------
//! Skip everything to the next: '*' or '\0'
@ -625,17 +599,17 @@ private:
// -------------------------------------------------------------------
//! Output a warning to the logger
//! \param szWarn Warn message
void LogWarning(const char* szWarn);
void LogWarning(const char *szWarn);
// -------------------------------------------------------------------
//! Output a message to the logger
//! \param szWarn Message
void LogInfo(const char* szWarn);
void LogInfo(const char *szWarn);
// -------------------------------------------------------------------
//! Output an error to the logger
//! \param szWarn Error message
AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void LogError(const char *szWarn) AI_WONT_RETURN_SUFFIX;
// -------------------------------------------------------------------
//! Parse a string, enclosed in double quotation marks
@ -643,12 +617,11 @@ private:
//! \param szName Name of the enclosing element -> used in error
//! messages.
//! \return false if an error occurred
bool ParseString(std::string& out,const char* szName);
bool ParseString(std::string &out, const char *szName);
public:
//! Pointer to current data
const char* filePtr;
const char *filePtr;
//! background color to be passed to the viewer
//! QNAN if none was found
@ -695,9 +668,8 @@ public:
unsigned int iFileFormat;
};
} // Namespace ASE
} // Namespace ASSIMP
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_3DS_IMPORTER

View File

@ -4,7 +4,6 @@ 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,

View File

@ -4,7 +4,6 @@ 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,
@ -54,16 +53,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOStream.hpp>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h>
#include <zlib.h>
#else
# include "../contrib/zlib/zlib.h"
#include "../contrib/zlib/zlib.h"
#endif
#include <time.h>
#ifdef _WIN32
# pragma warning(push)
# pragma warning(disable : 4706)
#pragma warning(push)
#pragma warning(disable : 4706)
#endif // _WIN32
namespace Assimp {
@ -269,7 +268,7 @@ private:
public:
AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) :
buffer(NULL),
buffer(nullptr),
magic(magic),
container(container),
cur_size(0),
@ -337,7 +336,7 @@ protected:
void WriteBinaryNode(IOStream *container, const aiNode *node) {
AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE);
unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
unsigned int nb_metadata = (node->mMetaData != nullptr ? node->mMetaData->mNumProperties : 0);
Write<aiString>(&chunk, node->mName);
Write<aiMatrix4x4>(&chunk, node->mTransformation);
@ -362,32 +361,32 @@ protected:
Write<uint16_t>(&chunk, (uint16_t)type);
switch (type) {
case AI_BOOL:
Write<bool>(&chunk, *((bool *)value));
break;
case AI_INT32:
Write<int32_t>(&chunk, *((int32_t *)value));
break;
case AI_UINT64:
Write<uint64_t>(&chunk, *((uint64_t *)value));
break;
case AI_FLOAT:
Write<float>(&chunk, *((float *)value));
break;
case AI_DOUBLE:
Write<double>(&chunk, *((double *)value));
break;
case AI_AISTRING:
Write<aiString>(&chunk, *((aiString *)value));
break;
case AI_AIVECTOR3D:
Write<aiVector3D>(&chunk, *((aiVector3D *)value));
break;
case AI_BOOL:
Write<bool>(&chunk, *((bool *)value));
break;
case AI_INT32:
Write<int32_t>(&chunk, *((int32_t *)value));
break;
case AI_UINT64:
Write<uint64_t>(&chunk, *((uint64_t *)value));
break;
case AI_FLOAT:
Write<float>(&chunk, *((float *)value));
break;
case AI_DOUBLE:
Write<double>(&chunk, *((double *)value));
break;
case AI_AISTRING:
Write<aiString>(&chunk, *((aiString *)value));
break;
case AI_AIVECTOR3D:
Write<aiVector3D>(&chunk, *((aiVector3D *)value));
break;
#ifdef SWIG
case FORCE_32BIT:
#endif // SWIG
default:
break;
default:
break;
}
}
}
@ -745,7 +744,7 @@ public:
};
try {
time_t tt = time(NULL);
time_t tt = time(nullptr);
#if _WIN32
tm *p = gmtime(&tt);
#else
@ -791,7 +790,7 @@ public:
// Up to here the data is uncompressed. For compressed files, the rest
// is compressed using standard DEFLATE from zlib.
if (compressed) {
AssbinChunkWriter uncompressedStream(NULL, 0);
AssbinChunkWriter uncompressedStream(nullptr, 0);
WriteBinaryScene(&uncompressedStream, pScene);
uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
@ -827,7 +826,7 @@ void DumpSceneToAssbin(
fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
}
#ifdef _WIN32
# pragma warning(pop)
#pragma warning(pop)
#endif // _WIN32
} // end of namespace Assimp

View File

@ -4,7 +4,6 @@ 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,
@ -54,12 +53,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
void ASSIMP_API DumpSceneToAssbin(
const char* pFile,
const char* cmd,
IOSystem* pIOSystem,
const aiScene* pScene,
bool shortened,
bool compressed);
const char *pFile,
const char *cmd,
IOSystem *pIOSystem,
const aiScene *pScene,
bool shortened,
bool compressed);
}

View File

@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
// internal headers
#include "Assbin/AssbinLoader.h"
#include "AssetLib/Assbin/AssbinLoader.h"
#include "Common/assbin_chunks.h"
#include <assimp/MemoryIOWrapper.h>
#include <assimp/anim.h>
@ -253,32 +253,32 @@ void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *pa
void *data = nullptr;
switch (node->mMetaData->mValues[i].mType) {
case AI_BOOL:
data = new bool(Read<bool>(stream));
break;
case AI_INT32:
data = new int32_t(Read<int32_t>(stream));
break;
case AI_UINT64:
data = new uint64_t(Read<uint64_t>(stream));
break;
case AI_FLOAT:
data = new ai_real(Read<ai_real>(stream));
break;
case AI_DOUBLE:
data = new double(Read<double>(stream));
break;
case AI_AISTRING:
data = new aiString(Read<aiString>(stream));
break;
case AI_AIVECTOR3D:
data = new aiVector3D(Read<aiVector3D>(stream));
break;
case AI_BOOL:
data = new bool(Read<bool>(stream));
break;
case AI_INT32:
data = new int32_t(Read<int32_t>(stream));
break;
case AI_UINT64:
data = new uint64_t(Read<uint64_t>(stream));
break;
case AI_FLOAT:
data = new ai_real(Read<ai_real>(stream));
break;
case AI_DOUBLE:
data = new double(Read<double>(stream));
break;
case AI_AISTRING:
data = new aiString(Read<aiString>(stream));
break;
case AI_AIVECTOR3D:
data = new aiVector3D(Read<aiVector3D>(stream));
break;
#ifndef SWIG
case FORCE_32BIT:
case FORCE_32BIT:
#endif // SWIG
default:
break;
default:
break;
}
node->mMetaData->mValues[i].mData = data;
@ -604,7 +604,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
// Read node graph
//scene->mRootNode = new aiNode[1];
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL);
ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr);
// Read all meshes
if (scene->mNumMeshes) {

View File

@ -9,6 +9,9 @@ For details, see http://sourceforge.net/projects/libb64
const int CHARS_PER_LINE = 72;
#pragma warning(push)
#pragma warning(disable : 4244)
void base64_init_encodestate(base64_encodestate* state_in)
{
state_in->step = step_A;
@ -107,3 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
return (int)(codechar - code_out);
}
#pragma warning(pop)

View File

@ -9,30 +9,31 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/Exceptional.h>
#include <sstream>
#include <limits>
#include <cassert>
#include <limits>
#include <memory>
#include <sstream>
#define CURRENT_FORMAT_VERSION 100
// grab scoped_ptr from assimp to avoid a dependency on boost.
// grab scoped_ptr from assimp to avoid a dependency on boost.
//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
#include "mesh_splitter.h"
extern "C" {
#include "cencode.h"
#include "cencode.h"
}
namespace Assimp {
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
class JSONWriter {
@ -42,10 +43,8 @@ public:
Flag_WriteSpecialFloats = 0x2,
};
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
: out(out)
, first()
, flags(flags) {
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
out(out), first(), flags(flags) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale
buff.imbue(std::locale("C"));
}
@ -68,30 +67,30 @@ public:
indent.erase(indent.end() - 1);
}
void Key(const std::string& name) {
void Key(const std::string &name) {
AddIndentation();
Delimit();
buff << '\"' + name + "\": ";
}
template<typename Literal>
void Element(const Literal& name) {
template <typename Literal>
void Element(const Literal &name) {
AddIndentation();
Delimit();
LiteralToString(buff, name) << '\n';
}
template<typename Literal>
void SimpleValue(const Literal& s) {
template <typename Literal>
void SimpleValue(const Literal &s) {
LiteralToString(buff, s) << '\n';
}
void SimpleValue(const void* buffer, size_t len) {
void SimpleValue(const void *buffer, size_t len) {
base64_encodestate s;
base64_init_encodestate(&s);
char* const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
@ -156,21 +155,20 @@ public:
void Delimit() {
if (!first) {
buff << ',';
}
else {
} else {
buff << ' ';
first = false;
}
}
private:
template<typename Literal>
std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
template <typename Literal>
std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
stream << s;
return stream;
}
std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
std::string t;
// escape backslashes and single quotes, both would render the JSON invalid if left as is
@ -189,10 +187,10 @@ private:
return stream;
}
std::stringstream& LiteralToString(std::stringstream& stream, float f) {
std::stringstream &LiteralToString(std::stringstream &stream, float f) {
if (!std::numeric_limits<float>::is_iec559) {
// on a non IEEE-754 platform, we make no assumptions about the representation or existence
// of special floating-point numbers.
// of special floating-point numbers.
stream << f;
return stream;
}
@ -228,7 +226,7 @@ private:
}
private:
Assimp::IOStream& out;
Assimp::IOStream &out;
std::string indent, newline;
std::stringstream buff;
bool first;
@ -236,7 +234,7 @@ private:
unsigned int flags;
};
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.Element(ai.x);
out.Element(ai.y);
@ -244,7 +242,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
out.EndArray();
}
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.Element(ai.w);
out.Element(ai.x);
@ -253,7 +251,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
out.EndArray();
}
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.Element(ai.r);
out.Element(ai.g);
@ -261,7 +259,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
out.EndArray();
}
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);
for (unsigned int x = 0; x < 4; ++x) {
for (unsigned int y = 0; y < 4; ++y) {
@ -271,7 +269,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
out.EndArray();
}
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.Key("name");
@ -292,7 +290,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
out.EndObj();
}
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);
for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
out.Element(ai.mIndices[i]);
@ -300,7 +298,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
out.EndArray();
}
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.Key("name");
@ -411,7 +409,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("name");
@ -441,13 +439,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("properties");
out.StartArray();
for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
const aiMaterialProperty* const prop = ai.mProperties[i];
const aiMaterialProperty *const prop = ai.mProperties[i];
out.StartObj(true);
out.Key("key");
out.SimpleValue(prop->mKey);
@ -461,46 +459,41 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
out.Key("value");
switch (prop->mType) {
case aiPTI_Float:
if (prop->mDataLength / sizeof(float) > 1) {
out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
out.Element(reinterpret_cast<float*>(prop->mData)[ii]);
}
out.EndArray();
case aiPTI_Float:
if (prop->mDataLength / sizeof(float) > 1) {
out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
}
else {
out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
}
break;
out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
}
break;
case aiPTI_Integer:
if (prop->mDataLength / sizeof(int) > 1) {
out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
out.Element(reinterpret_cast<int*>(prop->mData)[ii]);
}
out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
case aiPTI_Integer:
if (prop->mDataLength / sizeof(int) > 1) {
out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
}
break;
out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
}
break;
case aiPTI_String:
{
aiString s;
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
out.SimpleValue(s);
}
break;
case aiPTI_Buffer:
{
// binary data is written as series of hex-encoded octets
out.SimpleValue(prop->mData, prop->mDataLength);
}
break;
default:
assert(false);
case aiPTI_String: {
aiString s;
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
out.SimpleValue(s);
} break;
case aiPTI_Buffer: {
// binary data is written as series of hex-encoded octets
out.SimpleValue(prop->mData, prop->mDataLength);
} break;
default:
assert(false);
}
out.EndObj();
@ -510,7 +503,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("width");
@ -525,13 +518,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
out.Key("data");
if (!ai.mHeight) {
out.SimpleValue(ai.pcData, ai.mWidth);
}
else {
} else {
out.StartArray();
for (unsigned int y = 0; y < ai.mHeight; ++y) {
out.StartArray(true);
for (unsigned int x = 0; x < ai.mWidth; ++x) {
const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
out.StartArray(true);
out.Element(static_cast<unsigned int>(tx.r));
out.Element(static_cast<unsigned int>(tx.g));
@ -547,7 +539,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("name");
@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
if (ai.mType != aiLightSource_POINT) {
out.Key("direction");
Write(out, ai.mDirection, false);
}
if (ai.mType != aiLightSource_DIRECTIONAL) {
@ -596,7 +587,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("name");
@ -612,7 +603,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("positionkeys");
out.StartArray();
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
const aiVectorKey& pos = ai.mPositionKeys[n];
const aiVectorKey &pos = ai.mPositionKeys[n];
out.StartArray(true);
out.Element(pos.mTime);
Write(out, pos.mValue);
@ -625,7 +616,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("rotationkeys");
out.StartArray();
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
const aiQuatKey& rot = ai.mRotationKeys[n];
const aiQuatKey &rot = ai.mRotationKeys[n];
out.StartArray(true);
out.Element(rot.mTime);
Write(out, rot.mValue);
@ -638,7 +629,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("scalingkeys");
out.StartArray();
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
const aiVectorKey& scl = ai.mScalingKeys[n];
const aiVectorKey &scl = ai.mScalingKeys[n];
out.StartArray(true);
out.Element(scl.mTime);
Write(out, scl.mValue);
@ -649,7 +640,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("name");
@ -670,7 +661,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
out.EndObj();
}
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.Key("name");
@ -697,7 +688,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
out.EndObj();
}
void WriteFormatInfo(JSONWriter& out) {
void WriteFormatInfo(JSONWriter &out) {
out.StartObj();
out.Key("format");
out.SimpleValue("\"assimp2json\"");
@ -706,7 +697,7 @@ void WriteFormatInfo(JSONWriter& out) {
out.EndObj();
}
void Write(JSONWriter& out, const aiScene& ai) {
void Write(JSONWriter &out, const aiScene &ai) {
out.StartObj();
out.Key("__metadata__");
@ -774,15 +765,14 @@ void Write(JSONWriter& out, const aiScene& ai) {
out.EndObj();
}
void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
if (!str) {
//throw Assimp::DeadlyExportError("could not open output file");
throw DeadlyExportError("could not open output file");
}
// get a copy of the scene so we can modify it
aiScene* scenecopy_tmp;
aiScene *scenecopy_tmp;
aiCopyScene(scene, &scenecopy_tmp);
try {
@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
Write(s, *scenecopy_tmp);
}
catch (...) {
} catch (...) {
aiFreeScene(scenecopy_tmp);
throw;
}
aiFreeScene(scenecopy_tmp);
}
}
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
namespace Assimp {
namespace Assimp {
void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
{

View File

@ -0,0 +1,659 @@
/*
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 AssxmlFileWriter.cpp
* @brief Implementation of Assxml file writer.
*/
#include "AssxmlFileWriter.h"
#include "PostProcessing/ProcessHelper.h"
#include <assimp/version.h>
#include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <stdarg.h>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include <contrib/zlib/zlib.h>
#endif
#include <stdio.h>
#include <time.h>
#include <memory>
using namespace Assimp;
namespace Assimp {
namespace AssxmlFileWriter {
// -----------------------------------------------------------------------------------
static int ioprintf(IOStream *io, const char *format, ...) {
using namespace std;
if (nullptr == io) {
return -1;
}
static const int Size = 4096;
char sz[Size];
::memset(sz, '\0', Size);
va_list va;
va_start(va, format);
const unsigned int nSize = vsnprintf(sz, Size - 1, format, va);
ai_assert(nSize < Size);
va_end(va);
io->Write(sz, sizeof(char), nSize);
return nSize;
}
// -----------------------------------------------------------------------------------
// Convert a name to standard XML format
static void ConvertName(aiString &out, const aiString &in) {
out.length = 0;
for (unsigned int i = 0; i < in.length; ++i) {
switch (in.data[i]) {
case '<':
out.Append("&lt;");
break;
case '>':
out.Append("&gt;");
break;
case '&':
out.Append("&amp;");
break;
case '\"':
out.Append("&quot;");
break;
case '\'':
out.Append("&apos;");
break;
default:
out.data[out.length++] = in.data[i];
}
}
out.data[out.length] = 0;
}
// -----------------------------------------------------------------------------------
// Write a single node as text dump
static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
char prefix[512];
for (unsigned int i = 0; i < depth; ++i)
prefix[i] = '\t';
prefix[depth] = '\0';
const aiMatrix4x4 &m = node->mTransformation;
aiString name;
ConvertName(name, node->mName);
ioprintf(io, "%s<Node name=\"%s\"> \n"
"%s\t<Matrix4> \n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t</Matrix4> \n",
prefix, name.data, prefix,
prefix, m.a1, m.a2, m.a3, m.a4,
prefix, m.b1, m.b2, m.b3, m.b4,
prefix, m.c1, m.c2, m.c3, m.c4,
prefix, m.d1, m.d2, m.d3, m.d4, prefix);
if (node->mNumMeshes) {
ioprintf(io, "%s\t<MeshRefs num=\"%u\">\n%s\t",
prefix, node->mNumMeshes, prefix);
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
ioprintf(io, "%u ", node->mMeshes[i]);
}
ioprintf(io, "\n%s\t</MeshRefs>\n", prefix);
}
if (node->mNumChildren) {
ioprintf(io, "%s\t<NodeList num=\"%u\">\n",
prefix, node->mNumChildren);
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
WriteNode(node->mChildren[i], io, depth + 2);
}
ioprintf(io, "%s\t</NodeList>\n", prefix);
}
ioprintf(io, "%s</Node>\n", prefix);
}
// -----------------------------------------------------------------------------------
// 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
static std::string encodeXML(const std::string &data) {
std::string buffer;
buffer.reserve(data.size());
for (size_t pos = 0; pos != data.size(); ++pos) {
switch (data[pos]) {
case '&': buffer.append("&amp;"); break;
case '\"': buffer.append("&quot;"); break;
case '\'': buffer.append("&apos;"); break;
case '<': buffer.append("&lt;"); break;
case '>': buffer.append("&gt;"); break;
default: buffer.append(&data[pos], 1); break;
}
}
return buffer;
}
// -----------------------------------------------------------------------------------
// Write a text model dump
static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) {
time_t tt = ::time(nullptr);
#if _WIN32
tm *p = gmtime(&tt);
#else
struct tm now;
tm *p = gmtime_r(&tt, &now);
#endif
ai_assert(nullptr != p);
std::string c = cmd;
std::string::size_type s;
// https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632
// -- not allowed in XML comments
while ((s = c.find("--")) != std::string::npos) {
c[s] = '?';
}
// write header
std::string header(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<ASSIMP format_id=\"1\">\n\n"
"<!-- XML Model dump produced by assimp dump\n"
" Library version: %u.%u.%u\n"
" Source: %s\n"
" Command line: %s\n"
" %s\n"
"-->"
" \n\n"
"<Scene flags=\"%u\" postprocessing=\"%u\">\n");
const unsigned int majorVersion(aiGetVersionMajor());
const unsigned int minorVersion(aiGetVersionMinor());
const unsigned int rev(aiGetVersionRevision());
const char *curtime(asctime(p));
ioprintf(io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u);
// write the node graph
WriteNode(scene->mRootNode, io, 0);
#if 0
// write cameras
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
aiCamera* cam = scene->mCameras[i];
ConvertName(name,cam->mName);
// camera header
ioprintf(io,"\t<Camera parent=\"%s\">\n"
"\t\t<Vector3 name=\"up\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"fov\" > %f </Float>\n"
"\t\t<Float name=\"aspect\" > %f </Float>\n"
"\t\t<Float name=\"near_clip\" > %f </Float>\n"
"\t\t<Float name=\"far_clip\" > %f </Float>\n"
"\t</Camera>\n",
name.data,
cam->mUp.x,cam->mUp.y,cam->mUp.z,
cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
}
// write lights
for (unsigned int i = 0; i < scene->mNumLights;++i) {
aiLight* l = scene->mLights[i];
ConvertName(name,l->mName);
// light header
ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
"\t\t<Vector3 name=\"diffuse\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"specular\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"ambient\" > %0 8f %0 8f %0 8f </Vector3>\n",
name.data,
(l->mType == aiLightSource_DIRECTIONAL ? "directional" :
(l->mType == aiLightSource_POINT ? "point" : "spot" )),
l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
if (l->mType != aiLightSource_DIRECTIONAL) {
ioprintf(io,
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"atten_cst\" > %f </Float>\n"
"\t\t<Float name=\"atten_lin\" > %f </Float>\n"
"\t\t<Float name=\"atten_sqr\" > %f </Float>\n",
l->mPosition.x,l->mPosition.y,l->mPosition.z,
l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
}
if (l->mType != aiLightSource_POINT) {
ioprintf(io,
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n",
l->mDirection.x,l->mDirection.y,l->mDirection.z);
}
if (l->mType == aiLightSource_SPOT) {
ioprintf(io,
"\t\t<Float name=\"cone_out\" > %f </Float>\n"
"\t\t<Float name=\"cone_inn\" > %f </Float>\n",
l->mAngleOuterCone,l->mAngleInnerCone);
}
ioprintf(io,"\t</Light>\n");
}
#endif
aiString name;
// write textures
if (scene->mNumTextures) {
ioprintf(io, "<TextureList num=\"%u\">\n", scene->mNumTextures);
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
aiTexture *tex = scene->mTextures[i];
bool compressed = (tex->mHeight == 0);
// mesh header
ioprintf(io, "\t<Texture width=\"%u\" height=\"%u\" compressed=\"%s\"> \n",
(compressed ? -1 : tex->mWidth), (compressed ? -1 : tex->mHeight),
(compressed ? "true" : "false"));
if (compressed) {
ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth);
if (!shortened) {
for (unsigned int n = 0; n < tex->mWidth; ++n) {
ioprintf(io, "\t\t\t%2x", reinterpret_cast<uint8_t *>(tex->pcData)[n]);
if (n && !(n % 50)) {
ioprintf(io, "\n");
}
}
}
} else if (!shortened) {
ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth * tex->mHeight * 4);
// const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1;
for (unsigned int y = 0; y < tex->mHeight; ++y) {
for (unsigned int x = 0; x < tex->mWidth; ++x) {
aiTexel *tx = tex->pcData + y * tex->mWidth + x;
unsigned int r = tx->r, g = tx->g, b = tx->b, a = tx->a;
ioprintf(io, "\t\t\t%2x %2x %2x %2x", r, g, b, a);
// group by four for readability
if (0 == (x + y * tex->mWidth) % 4) {
ioprintf(io, "\n");
}
}
}
}
ioprintf(io, "\t\t</Data>\n\t</Texture>\n");
}
ioprintf(io, "</TextureList>\n");
}
// write materials
if (scene->mNumMaterials) {
ioprintf(io, "<MaterialList num=\"%u\">\n", scene->mNumMaterials);
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
const aiMaterial *mat = scene->mMaterials[i];
ioprintf(io, "\t<Material>\n");
ioprintf(io, "\t\t<MatPropertyList num=\"%u\">\n", mat->mNumProperties);
for (unsigned int n = 0; n < mat->mNumProperties; ++n) {
const aiMaterialProperty *prop = mat->mProperties[n];
const char *sz = "";
if (prop->mType == aiPTI_Float) {
sz = "float";
} else if (prop->mType == aiPTI_Integer) {
sz = "integer";
} else if (prop->mType == aiPTI_String) {
sz = "string";
} else if (prop->mType == aiPTI_Buffer) {
sz = "binary_buffer";
}
ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
prop->mKey.data, sz,
::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
if (prop->mType == aiPTI_Float) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength / sizeof(float)));
for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(float); ++pp) {
ioprintf(io, "%f ", *((float *)(prop->mData + pp * sizeof(float))));
}
} else if (prop->mType == aiPTI_Integer) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength / sizeof(int)));
for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(int); ++pp) {
ioprintf(io, "%i ", *((int *)(prop->mData + pp * sizeof(int))));
}
} else if (prop->mType == aiPTI_Buffer) {
ioprintf(io, " size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength));
for (unsigned int pp = 0; pp < prop->mDataLength; ++pp) {
ioprintf(io, "%2x ", prop->mData[pp]);
if (pp && 0 == pp % 30) {
ioprintf(io, "\n\t\t\t\t");
}
}
} else if (prop->mType == aiPTI_String) {
ioprintf(io, ">\n\t\t\t\t\"%s\"", encodeXML(prop->mData + 4).c_str() /* skip length */);
}
ioprintf(io, "\n\t\t\t</MatProperty>\n");
}
ioprintf(io, "\t\t</MatPropertyList>\n");
ioprintf(io, "\t</Material>\n");
}
ioprintf(io, "</MaterialList>\n");
}
// write animations
if (scene->mNumAnimations) {
ioprintf(io, "<AnimationList num=\"%u\">\n", scene->mNumAnimations);
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
aiAnimation *anim = scene->mAnimations[i];
// anim header
ConvertName(name, anim->mName);
ioprintf(io, "\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
name.data, anim->mDuration, anim->mTicksPerSecond);
// write bone animation channels
if (anim->mNumChannels) {
ioprintf(io, "\t\t<NodeAnimList num=\"%u\">\n", anim->mNumChannels);
for (unsigned int n = 0; n < anim->mNumChannels; ++n) {
aiNodeAnim *nd = anim->mChannels[n];
// node anim header
ConvertName(name, nd->mNodeName);
ioprintf(io, "\t\t\t<NodeAnim node=\"%s\">\n", name.data);
if (!shortened) {
// write position keys
if (nd->mNumPositionKeys) {
ioprintf(io, "\t\t\t\t<PositionKeyList num=\"%u\">\n", nd->mNumPositionKeys);
for (unsigned int a = 0; a < nd->mNumPositionKeys; ++a) {
aiVectorKey *vc = nd->mPositionKeys + a;
ioprintf(io, "\t\t\t\t\t<PositionKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
}
ioprintf(io, "\t\t\t\t</PositionKeyList>\n");
}
// write scaling keys
if (nd->mNumScalingKeys) {
ioprintf(io, "\t\t\t\t<ScalingKeyList num=\"%u\">\n", nd->mNumScalingKeys);
for (unsigned int a = 0; a < nd->mNumScalingKeys; ++a) {
aiVectorKey *vc = nd->mScalingKeys + a;
ioprintf(io, "\t\t\t\t\t<ScalingKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
}
ioprintf(io, "\t\t\t\t</ScalingKeyList>\n");
}
// write rotation keys
if (nd->mNumRotationKeys) {
ioprintf(io, "\t\t\t\t<RotationKeyList num=\"%u\">\n", nd->mNumRotationKeys);
for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) {
aiQuatKey *vc = nd->mRotationKeys + a;
ioprintf(io, "\t\t\t\t\t<RotationKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z, vc->mValue.w);
}
ioprintf(io, "\t\t\t\t</RotationKeyList>\n");
}
}
ioprintf(io, "\t\t\t</NodeAnim>\n");
}
ioprintf(io, "\t\t</NodeAnimList>\n");
}
ioprintf(io, "\t</Animation>\n");
}
ioprintf(io, "</AnimationList>\n");
}
// write meshes
if (scene->mNumMeshes) {
ioprintf(io, "<MeshList num=\"%u\">\n", scene->mNumMeshes);
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
aiMesh *mesh = scene->mMeshes[i];
// const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1;
// mesh header
ioprintf(io, "\t<Mesh types=\"%s %s %s %s\" material_index=\"%u\">\n",
(mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""),
mesh->mMaterialIndex);
// bones
if (mesh->mNumBones) {
ioprintf(io, "\t\t<BoneList num=\"%u\">\n", mesh->mNumBones);
for (unsigned int n = 0; n < mesh->mNumBones; ++n) {
aiBone *bone = mesh->mBones[n];
ConvertName(name, bone->mName);
// bone header
ioprintf(io, "\t\t\t<Bone name=\"%s\">\n"
"\t\t\t\t<Matrix4> \n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t</Matrix4> \n",
name.data,
bone->mOffsetMatrix.a1, bone->mOffsetMatrix.a2, bone->mOffsetMatrix.a3, bone->mOffsetMatrix.a4,
bone->mOffsetMatrix.b1, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.b4,
bone->mOffsetMatrix.c1, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.c4,
bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3, bone->mOffsetMatrix.d4);
if (!shortened && bone->mNumWeights) {
ioprintf(io, "\t\t\t\t<WeightList num=\"%u\">\n", bone->mNumWeights);
// bone weights
for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
aiVertexWeight *wght = bone->mWeights + a;
ioprintf(io, "\t\t\t\t\t<Weight index=\"%u\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
wght->mVertexId, wght->mWeight);
}
ioprintf(io, "\t\t\t\t</WeightList>\n");
}
ioprintf(io, "\t\t\t</Bone>\n");
}
ioprintf(io, "\t\t</BoneList>\n");
}
// faces
if (!shortened && mesh->mNumFaces) {
ioprintf(io, "\t\t<FaceList num=\"%u\">\n", mesh->mNumFaces);
for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
aiFace &f = mesh->mFaces[n];
ioprintf(io, "\t\t\t<Face num=\"%u\">\n"
"\t\t\t\t",
f.mNumIndices);
for (unsigned int j = 0; j < f.mNumIndices; ++j)
ioprintf(io, "%u ", f.mIndices[j]);
ioprintf(io, "\n\t\t\t</Face>\n");
}
ioprintf(io, "\t\t</FaceList>\n");
}
// vertex positions
if (mesh->HasPositions()) {
ioprintf(io, "\t\t<Positions num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mVertices[n].x,
mesh->mVertices[n].y,
mesh->mVertices[n].z);
}
}
ioprintf(io, "\t\t</Positions>\n");
}
// vertex normals
if (mesh->HasNormals()) {
ioprintf(io, "\t\t<Normals num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mNormals[n].x,
mesh->mNormals[n].y,
mesh->mNormals[n].z);
}
}
ioprintf(io, "\t\t</Normals>\n");
}
// vertex tangents and bitangents
if (mesh->HasTangentsAndBitangents()) {
ioprintf(io, "\t\t<Tangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mTangents[n].x,
mesh->mTangents[n].y,
mesh->mTangents[n].z);
}
}
ioprintf(io, "\t\t</Tangents>\n");
ioprintf(io, "\t\t<Bitangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mBitangents[n].x,
mesh->mBitangents[n].y,
mesh->mBitangents[n].z);
}
}
ioprintf(io, "\t\t</Bitangents>\n");
}
// texture coordinates
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (!mesh->mTextureCoords[a])
break;
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" num_components=\"%u\"> \n", mesh->mNumVertices,
a, mesh->mNumUVComponents[a]);
if (!shortened) {
if (mesh->mNumUVComponents[a] == 3) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y,
mesh->mTextureCoords[a][n].z);
}
} else {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y);
}
}
}
ioprintf(io, "\t\t</TextureCoords>\n");
}
// vertex colors
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
if (!mesh->mColors[a])
break;
ioprintf(io, "\t\t<Colors num=\"%u\" set=\"%u\" num_components=\"4\"> \n", mesh->mNumVertices, a);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io, "\t\t%0 8f %0 8f %0 8f %0 8f\n",
mesh->mColors[a][n].r,
mesh->mColors[a][n].g,
mesh->mColors[a][n].b,
mesh->mColors[a][n].a);
}
}
ioprintf(io, "\t\t</Colors>\n");
}
ioprintf(io, "\t</Mesh>\n");
}
ioprintf(io, "</MeshList>\n");
}
ioprintf(io, "</Scene>\n</ASSIMP>");
}
} // end of namespace AssxmlFileWriter
void DumpSceneToAssxml(
const char *pFile, const char *cmd, IOSystem *pIOSystem,
const aiScene *pScene, bool shortened) {
std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt"));
if (!file.get()) {
throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
}
AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened);
}
} // end of namespace Assimp

View File

@ -0,0 +1,744 @@
/*
---------------------------------------------------------------------------
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 B3DImporter.cpp
* @brief Implementation of the b3d importer class
*/
#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
// internal headers
#include "AssetLib/B3D/B3DImporter.h"
#include "PostProcessing/ConvertToLHProcess.h"
#include "PostProcessing/TextureTransform.h"
#include <assimp/StringUtils.h>
#include <assimp/anim.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp;
using namespace std;
static const aiImporterDesc desc = {
"BlitzBasic 3D Importer",
"",
"",
"http://www.blitzbasic.com/",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"b3d"
};
#ifdef _MSC_VER
#pragma warning(disable : 4018)
#endif
//#define DEBUG_B3D
template <typename T>
void DeleteAllBarePointers(std::vector<T> &x) {
for (auto p : x) {
delete p;
}
}
B3DImporter::~B3DImporter() {
}
// ------------------------------------------------------------------------------------------------
bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
size_t pos = pFile.find_last_of('.');
if (pos == string::npos) {
return false;
}
string ext = pFile.substr(pos + 1);
if (ext.size() != 3) {
return false;
}
return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D');
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc *B3DImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open B3D file " + pFile + ".");
}
// check whether the .b3d file is large enough to contain
// at least one chunk.
size_t fileSize = file->FileSize();
if (fileSize < 8) {
throw DeadlyImportError("B3D File is too small.");
}
_pos = 0;
_buf.resize(fileSize);
file->Read(&_buf[0], 1, fileSize);
_stack.clear();
ReadBB3D(pScene);
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Oops() {
throw DeadlyImportError("B3D Importer - INTERNAL ERROR");
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail(string str) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
#endif
throw DeadlyImportError("B3D Importer - error in B3D file data: " + str);
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte() {
if (_pos > _buf.size()) {
Fail("EOF");
}
return _buf[_pos++];
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadInt() {
if (_pos + 4 > _buf.size()) {
Fail("EOF");
}
int n;
memcpy(&n, &_buf[_pos], 4);
_pos += 4;
return n;
}
// ------------------------------------------------------------------------------------------------
float B3DImporter::ReadFloat() {
if (_pos + 4 > _buf.size()) {
Fail("EOF");
}
float n;
memcpy(&n, &_buf[_pos], 4);
_pos += 4;
return n;
}
// ------------------------------------------------------------------------------------------------
aiVector2D B3DImporter::ReadVec2() {
float x = ReadFloat();
float y = ReadFloat();
return aiVector2D(x, y);
}
// ------------------------------------------------------------------------------------------------
aiVector3D B3DImporter::ReadVec3() {
float x = ReadFloat();
float y = ReadFloat();
float z = ReadFloat();
return aiVector3D(x, y, z);
}
// ------------------------------------------------------------------------------------------------
aiQuaternion B3DImporter::ReadQuat() {
// (aramis_acg) Fix to adapt the loader to changed quat orientation
float w = -ReadFloat();
float x = ReadFloat();
float y = ReadFloat();
float z = ReadFloat();
return aiQuaternion(w, x, y, z);
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadString() {
if (_pos > _buf.size()) {
Fail("EOF");
}
string str;
while (_pos < _buf.size()) {
char c = (char)ReadByte();
if (!c) {
return str;
}
str += c;
}
return string();
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadChunk() {
string tag;
for (int i = 0; i < 4; ++i) {
tag += char(ReadByte());
}
#ifdef DEBUG_B3D
ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
#endif
unsigned sz = (unsigned)ReadInt();
_stack.push_back(_pos + sz);
return tag;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ExitChunk() {
_pos = _stack.back();
_stack.pop_back();
}
// ------------------------------------------------------------------------------------------------
size_t B3DImporter::ChunkSize() {
return _stack.back() - _pos;
}
// ------------------------------------------------------------------------------------------------
template <class T>
T *B3DImporter::to_array(const vector<T> &v) {
if (v.empty()) {
return 0;
}
T *p = new T[v.size()];
for (size_t i = 0; i < v.size(); ++i) {
p[i] = v[i];
}
return p;
}
// ------------------------------------------------------------------------------------------------
template <class T>
T **unique_to_array(vector<std::unique_ptr<T>> &v) {
if (v.empty()) {
return 0;
}
T **p = new T *[v.size()];
for (size_t i = 0; i < v.size(); ++i) {
p[i] = v[i].release();
}
return p;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTEXS() {
while (ChunkSize()) {
string name = ReadString();
/*int flags=*/ReadInt();
/*int blend=*/ReadInt();
/*aiVector2D pos=*/ReadVec2();
/*aiVector2D scale=*/ReadVec2();
/*float rot=*/ReadFloat();
_textures.push_back(name);
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBRUS() {
int n_texs = ReadInt();
if (n_texs < 0 || n_texs > 8) {
Fail("Bad texture count");
}
while (ChunkSize()) {
string name = ReadString();
aiVector3D color = ReadVec3();
float alpha = ReadFloat();
float shiny = ReadFloat();
/*int blend=**/ ReadInt();
int fx = ReadInt();
std::unique_ptr<aiMaterial> mat(new aiMaterial);
// Name
aiString ainame(name);
mat->AddProperty(&ainame, AI_MATKEY_NAME);
// Diffuse color
mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
// Opacity
mat->AddProperty(&alpha, 1, AI_MATKEY_OPACITY);
// Specular color
aiColor3D speccolor(shiny, shiny, shiny);
mat->AddProperty(&speccolor, 1, AI_MATKEY_COLOR_SPECULAR);
// Specular power
float specpow = shiny * 128;
mat->AddProperty(&specpow, 1, AI_MATKEY_SHININESS);
// Double sided
if (fx & 0x10) {
int i = 1;
mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
}
//Textures
for (int i = 0; i < n_texs; ++i) {
int texid = ReadInt();
if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) {
Fail("Bad texture id");
}
if (i == 0 && texid >= 0) {
aiString texname(_textures[texid]);
mat->AddProperty(&texname, AI_MATKEY_TEXTURE_DIFFUSE(0));
}
}
_materials.emplace_back(std::move(mat));
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadVRTS() {
_vflags = ReadInt();
_tcsets = ReadInt();
_tcsize = ReadInt();
if (_tcsets < 0 || _tcsets > 4 || _tcsize < 0 || _tcsize > 4) {
Fail("Bad texcoord data");
}
int sz = 12 + (_vflags & 1 ? 12 : 0) + (_vflags & 2 ? 16 : 0) + (_tcsets * _tcsize * 4);
size_t n_verts = ChunkSize() / sz;
int v0 = static_cast<int>(_vertices.size());
_vertices.resize(v0 + n_verts);
for (unsigned int i = 0; i < n_verts; ++i) {
Vertex &v = _vertices[v0 + i];
memset(v.bones, 0, sizeof(v.bones));
memset(v.weights, 0, sizeof(v.weights));
v.vertex = ReadVec3();
if (_vflags & 1) {
v.normal = ReadVec3();
}
if (_vflags & 2) {
ReadQuat(); //skip v 4bytes...
}
for (int j = 0; j < _tcsets; ++j) {
float t[4] = { 0, 0, 0, 0 };
for (int k = 0; k < _tcsize; ++k) {
t[k] = ReadFloat();
}
t[1] = 1 - t[1];
if (!j) {
v.texcoords = aiVector3D(t[0], t[1], t[2]);
}
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTRIS(int v0) {
int matid = ReadInt();
if (matid == -1) {
matid = 0;
} else if (matid < 0 || matid >= (int)_materials.size()) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("material id=", matid);
#endif
Fail("Bad material id");
}
std::unique_ptr<aiMesh> mesh(new aiMesh);
mesh->mMaterialIndex = matid;
mesh->mNumFaces = 0;
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
size_t n_tris = ChunkSize() / 12;
aiFace *face = mesh->mFaces = new aiFace[n_tris];
for (unsigned int i = 0; i < n_tris; ++i) {
int i0 = ReadInt() + v0;
int i1 = 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()) {
#ifdef DEBUG_B3D
ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
#endif
Fail("Bad triangle index");
continue;
}
face->mNumIndices = 3;
face->mIndices = new unsigned[3];
face->mIndices[0] = i0;
face->mIndices[1] = i1;
face->mIndices[2] = i2;
++mesh->mNumFaces;
++face;
}
_meshes.emplace_back(std::move(mesh));
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadMESH() {
/*int matid=*/ReadInt();
int v0 = static_cast<int>(_vertices.size());
while (ChunkSize()) {
string t = ReadChunk();
if (t == "VRTS") {
ReadVRTS();
} else if (t == "TRIS") {
ReadTRIS(v0);
}
ExitChunk();
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBONE(int id) {
while (ChunkSize()) {
int vertex = ReadInt();
float weight = ReadFloat();
if (vertex < 0 || vertex >= (int)_vertices.size()) {
Fail("Bad vertex index");
}
Vertex &v = _vertices[vertex];
for (int i = 0; i < 4; ++i) {
if (!v.weights[i]) {
v.bones[i] = static_cast<unsigned char>(id);
v.weights[i] = weight;
break;
}
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
vector<aiVectorKey> trans, scale;
vector<aiQuatKey> rot;
int flags = ReadInt();
while (ChunkSize()) {
int frame = ReadInt();
if (flags & 1) {
trans.push_back(aiVectorKey(frame, ReadVec3()));
}
if (flags & 2) {
scale.push_back(aiVectorKey(frame, ReadVec3()));
}
if (flags & 4) {
rot.push_back(aiQuatKey(frame, ReadQuat()));
}
}
if (flags & 1) {
nodeAnim->mNumPositionKeys = static_cast<unsigned int>(trans.size());
nodeAnim->mPositionKeys = to_array(trans);
}
if (flags & 2) {
nodeAnim->mNumScalingKeys = static_cast<unsigned int>(scale.size());
nodeAnim->mScalingKeys = to_array(scale);
}
if (flags & 4) {
nodeAnim->mNumRotationKeys = static_cast<unsigned int>(rot.size());
nodeAnim->mRotationKeys = to_array(rot);
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadANIM() {
/*int flags=*/ReadInt();
int frames = ReadInt();
float fps = ReadFloat();
std::unique_ptr<aiAnimation> anim(new aiAnimation);
anim->mDuration = frames;
anim->mTicksPerSecond = fps;
_animations.emplace_back(std::move(anim));
}
// ------------------------------------------------------------------------------------------------
aiNode *B3DImporter::ReadNODE(aiNode *parent) {
string name = ReadString();
aiVector3D t = ReadVec3();
aiVector3D s = ReadVec3();
aiQuaternion r = ReadQuat();
aiMatrix4x4 trans, scale, rot;
aiMatrix4x4::Translation(t, trans);
aiMatrix4x4::Scaling(s, scale);
rot = aiMatrix4x4(r.GetMatrix());
aiMatrix4x4 tform = trans * rot * scale;
int nodeid = static_cast<int>(_nodes.size());
aiNode *node = new aiNode(name);
_nodes.push_back(node);
node->mParent = parent;
node->mTransformation = tform;
std::unique_ptr<aiNodeAnim> nodeAnim;
vector<unsigned> meshes;
vector<aiNode *> children;
while (ChunkSize()) {
const string chunk = ReadChunk();
if (chunk == "MESH") {
unsigned int n = static_cast<unsigned int>(_meshes.size());
ReadMESH();
for (unsigned int i = n; i < static_cast<unsigned int>(_meshes.size()); ++i) {
meshes.push_back(i);
}
} else if (chunk == "BONE") {
ReadBONE(nodeid);
} else if (chunk == "ANIM") {
ReadANIM();
} else if (chunk == "KEYS") {
if (!nodeAnim) {
nodeAnim.reset(new aiNodeAnim);
nodeAnim->mNodeName = node->mName;
}
ReadKEYS(nodeAnim.get());
} else if (chunk == "NODE") {
aiNode *child = ReadNODE(node);
children.push_back(child);
}
ExitChunk();
}
if (nodeAnim) {
_nodeAnims.emplace_back(std::move(nodeAnim));
}
node->mNumMeshes = static_cast<unsigned int>(meshes.size());
node->mMeshes = to_array(meshes);
node->mNumChildren = static_cast<unsigned int>(children.size());
node->mChildren = to_array(children);
return node;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBB3D(aiScene *scene) {
_textures.clear();
_materials.clear();
_vertices.clear();
_meshes.clear();
DeleteAllBarePointers(_nodes);
_nodes.clear();
_nodeAnims.clear();
_animations.clear();
string t = ReadChunk();
if (t == "BB3D") {
int version = ReadInt();
if (!DefaultLogger::isNullLogger()) {
char dmp[128];
ai_snprintf(dmp, 128, "B3D file format version: %i", version);
ASSIMP_LOG_INFO(dmp);
}
while (ChunkSize()) {
const string chunk = ReadChunk();
if (chunk == "TEXS") {
ReadTEXS();
} else if (chunk == "BRUS") {
ReadBRUS();
} else if (chunk == "NODE") {
ReadNODE(0);
}
ExitChunk();
}
}
ExitChunk();
if (!_nodes.size()) {
Fail("No nodes");
}
if (!_meshes.size()) {
Fail("No meshes");
}
// Fix nodes/meshes/bones
for (size_t i = 0; i < _nodes.size(); ++i) {
aiNode *node = _nodes[i];
for (size_t j = 0; j < node->mNumMeshes; ++j) {
aiMesh *mesh = _meshes[node->mMeshes[j]].get();
int n_tris = mesh->mNumFaces;
int n_verts = mesh->mNumVertices = n_tris * 3;
aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = 0, *mc = 0;
if (_vflags & 1) {
mn = mesh->mNormals = new aiVector3D[n_verts];
}
if (_tcsets) {
mc = mesh->mTextureCoords[0] = new aiVector3D[n_verts];
}
aiFace *face = mesh->mFaces;
vector<vector<aiVertexWeight>> vweights(_nodes.size());
for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) {
for (int faceIndex = 0; faceIndex < 3; ++faceIndex) {
Vertex &v = _vertices[face->mIndices[faceIndex]];
*mv++ = v.vertex;
if (mn) *mn++ = v.normal;
if (mc) *mc++ = v.texcoords;
face->mIndices[faceIndex] = vertIdx + faceIndex;
for (int k = 0; k < 4; ++k) {
if (!v.weights[k])
break;
int bone = v.bones[k];
float weight = v.weights[k];
vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight));
}
}
++face;
}
vector<aiBone *> bones;
for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) {
vector<aiVertexWeight> &weights = vweights[weightIndx];
if (!weights.size()) {
continue;
}
aiBone *bone = new aiBone;
bones.push_back(bone);
aiNode *bnode = _nodes[weightIndx];
bone->mName = bnode->mName;
bone->mNumWeights = static_cast<unsigned int>(weights.size());
bone->mWeights = to_array(weights);
aiMatrix4x4 mat = bnode->mTransformation;
while (bnode->mParent) {
bnode = bnode->mParent;
mat = bnode->mTransformation * mat;
}
bone->mOffsetMatrix = mat.Inverse();
}
mesh->mNumBones = static_cast<unsigned int>(bones.size());
mesh->mBones = to_array(bones);
}
}
//nodes
scene->mRootNode = _nodes[0];
_nodes.clear(); // node ownership now belongs to scene
//material
if (!_materials.size()) {
_materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial));
}
scene->mNumMaterials = static_cast<unsigned int>(_materials.size());
scene->mMaterials = unique_to_array(_materials);
//meshes
scene->mNumMeshes = static_cast<unsigned int>(_meshes.size());
scene->mMeshes = unique_to_array(_meshes);
//animations
if (_animations.size() == 1 && _nodeAnims.size()) {
aiAnimation *anim = _animations.back().get();
anim->mNumChannels = static_cast<unsigned int>(_nodeAnims.size());
anim->mChannels = unique_to_array(_nodeAnims);
scene->mNumAnimations = static_cast<unsigned int>(_animations.size());
scene->mAnimations = unique_to_array(_animations);
}
// convert to RH
MakeLeftHandedProcess makeleft;
makeleft.Execute(scene);
FlipWindingOrderProcess flip;
flip.Execute(scene);
}
#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

View File

@ -42,19 +42,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
#include "BVHLoader.h"
#include <assimp/fast_atof.h>
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/Importer.hpp>
#include <memory>
#include <assimp/TinyFormatter.h>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/Importer.hpp>
#include <map>
#include <memory>
using namespace Assimp;
using namespace Assimp::Formatter;
@ -74,56 +73,50 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BVHLoader::BVHLoader()
: mLine(),
mAnimTickDuration(),
mAnimNumFrames(),
noSkeletonMesh()
{}
BVHLoader::BVHLoader() :
mLine(),
mAnimTickDuration(),
mAnimNumFrames(),
noSkeletonMesh() {}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BVHLoader::~BVHLoader()
{}
BVHLoader::~BVHLoader() {}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
{
bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
// check file extension
const std::string extension = GetExtension(pFile);
if( extension == "bvh")
if (extension == "bvh")
return true;
if ((!extension.length() || cs) && pIOHandler) {
const char* tokens[] = {"HIERARCHY"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
const char *tokens[] = { "HIERARCHY" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
void BVHLoader::SetupProperties(const Importer* pImp)
{
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
void BVHLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc* BVHLoader::GetInfo () const
{
const aiImporterDesc *BVHLoader::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
mFileName = pFile;
// read file into memory
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
if (file.get() == nullptr) {
throw DeadlyImportError("Failed to open file " + pFile + ".");
}
@ -133,47 +126,45 @@ void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSys
throw DeadlyImportError("File is too small.");
}
mBuffer.resize( fileSize);
file->Read( &mBuffer.front(), 1, fileSize);
mBuffer.resize(fileSize);
file->Read(&mBuffer.front(), 1, fileSize);
// start reading
mReader = mBuffer.begin();
mLine = 1;
ReadStructure( pScene);
ReadStructure(pScene);
if (!noSkeletonMesh) {
// build a dummy mesh for the skeleton so that we see something at least
SkeletonMeshBuilder meshBuilder( pScene);
SkeletonMeshBuilder meshBuilder(pScene);
}
// construct an animation from all the motion data we read
CreateAnimation( pScene);
CreateAnimation(pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the file
void BVHLoader::ReadStructure( aiScene* pScene)
{
void BVHLoader::ReadStructure(aiScene *pScene) {
// first comes hierarchy
std::string header = GetNextToken();
if( header != "HIERARCHY")
ThrowException( "Expected header string \"HIERARCHY\".");
ReadHierarchy( pScene);
if (header != "HIERARCHY")
ThrowException("Expected header string \"HIERARCHY\".");
ReadHierarchy(pScene);
// then comes the motion data
std::string motion = GetNextToken();
if( motion != "MOTION")
ThrowException( "Expected beginning of motion data \"MOTION\".");
ReadMotion( pScene);
if (motion != "MOTION")
ThrowException("Expected beginning of motion data \"MOTION\".");
ReadMotion(pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the hierarchy
void BVHLoader::ReadHierarchy( aiScene* pScene)
{
void BVHLoader::ReadHierarchy(aiScene *pScene) {
std::string root = GetNextToken();
if( root != "ROOT")
ThrowException( "Expected root node \"ROOT\".");
if (root != "ROOT")
ThrowException("Expected root node \"ROOT\".");
// Go read the hierarchy from here
pScene->mRootNode = ReadNode();
@ -181,73 +172,64 @@ void BVHLoader::ReadHierarchy( aiScene* pScene)
// ------------------------------------------------------------------------------------------------
// Reads a node and recursively its childs and returns the created node;
aiNode* BVHLoader::ReadNode()
{
aiNode *BVHLoader::ReadNode() {
// first token is name
std::string nodeName = GetNextToken();
if( nodeName.empty() || nodeName == "{")
ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." );
if (nodeName.empty() || nodeName == "{")
ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
// then an opening brace should follow
std::string openBrace = GetNextToken();
if( openBrace != "{")
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." );
if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
// Create a node
aiNode* node = new aiNode( nodeName);
std::vector<aiNode*> childNodes;
aiNode *node = new aiNode(nodeName);
std::vector<aiNode *> childNodes;
// and create an bone entry for it
mNodes.push_back( Node( node));
Node& internNode = mNodes.back();
mNodes.push_back(Node(node));
Node &internNode = mNodes.back();
// now read the node's contents
std::string siteToken;
while( 1)
{
while (1) {
std::string token = GetNextToken();
// node offset to parent node
if( token == "OFFSET")
ReadNodeOffset( node);
else if( token == "CHANNELS")
ReadNodeChannels( internNode);
else if( token == "JOINT")
{
if (token == "OFFSET")
ReadNodeOffset(node);
else if (token == "CHANNELS")
ReadNodeChannels(internNode);
else if (token == "JOINT") {
// child node follows
aiNode* child = ReadNode();
aiNode *child = ReadNode();
child->mParent = node;
childNodes.push_back( child);
}
else if( token == "End")
{
childNodes.push_back(child);
} else if (token == "End") {
// The real symbol is "End Site". Second part comes in a separate token
siteToken.clear();
siteToken = GetNextToken();
if( siteToken != "Site")
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
if (siteToken != "Site")
ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
aiNode* child = ReadEndSite( nodeName);
aiNode *child = ReadEndSite(nodeName);
child->mParent = node;
childNodes.push_back( child);
}
else if( token == "}")
{
childNodes.push_back(child);
} else if (token == "}") {
// we're done with that part of the hierarchy
break;
} else
{
} else {
// everything else is a parse error
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
ThrowException(format() << "Unknown keyword \"" << token << "\".");
}
}
// add the child nodes if there are any
if( childNodes.size() > 0)
{
if (childNodes.size() > 0) {
node->mNumChildren = static_cast<unsigned int>(childNodes.size());
node->mChildren = new aiNode*[node->mNumChildren];
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
node->mChildren = new aiNode *[node->mNumChildren];
std::copy(childNodes.begin(), childNodes.end(), node->mChildren);
}
// and return the sub-hierarchy we built here
@ -256,31 +238,30 @@ aiNode* BVHLoader::ReadNode()
// ------------------------------------------------------------------------------------------------
// Reads an end node and returns the created node.
aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
{
aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
// check opening brace
std::string openBrace = GetNextToken();
if( openBrace != "{")
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
// 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"
std::string token;
while( 1) {
while (1) {
token.clear();
token = GetNextToken();
// end node's offset
if( token == "OFFSET") {
ReadNodeOffset( node);
} else if( token == "}") {
if (token == "OFFSET") {
ReadNodeOffset(node);
} else if (token == "}") {
// we're done with the end node
break;
} else {
// everything else is a parse error
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
ThrowException(format() << "Unknown keyword \"" << token << "\".");
}
}
@ -289,8 +270,7 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
}
// ------------------------------------------------------------------------------------------------
// Reads a node offset for the given node
void BVHLoader::ReadNodeOffset( aiNode* pNode)
{
void BVHLoader::ReadNodeOffset(aiNode *pNode) {
// Offset consists of three floats to read
aiVector3D offset;
offset.x = GetNextTokenAsFloat();
@ -298,74 +278,69 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
offset.z = GetNextTokenAsFloat();
// build a transformation matrix from it
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z,
0.0f, 0.0f, 0.0f, 1.0f);
pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x,
0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z,
0.0f, 0.0f, 0.0f, 1.0f);
}
// ------------------------------------------------------------------------------------------------
// Reads the animation channels for the given node
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
{
void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
// number of channels. Use the float reader because we're lazy
float numChannelsFloat = GetNextTokenAsFloat();
unsigned int numChannels = (unsigned int) numChannelsFloat;
unsigned int numChannels = (unsigned int)numChannelsFloat;
for( unsigned int a = 0; a < numChannels; a++)
{
for (unsigned int a = 0; a < numChannels; a++) {
std::string channelToken = GetNextToken();
if( channelToken == "Xposition")
pNode.mChannels.push_back( Channel_PositionX);
else if( channelToken == "Yposition")
pNode.mChannels.push_back( Channel_PositionY);
else if( channelToken == "Zposition")
pNode.mChannels.push_back( Channel_PositionZ);
else if( channelToken == "Xrotation")
pNode.mChannels.push_back( Channel_RotationX);
else if( channelToken == "Yrotation")
pNode.mChannels.push_back( Channel_RotationY);
else if( channelToken == "Zrotation")
pNode.mChannels.push_back( Channel_RotationZ);
if (channelToken == "Xposition")
pNode.mChannels.push_back(Channel_PositionX);
else if (channelToken == "Yposition")
pNode.mChannels.push_back(Channel_PositionY);
else if (channelToken == "Zposition")
pNode.mChannels.push_back(Channel_PositionZ);
else if (channelToken == "Xrotation")
pNode.mChannels.push_back(Channel_RotationX);
else if (channelToken == "Yrotation")
pNode.mChannels.push_back(Channel_RotationY);
else if (channelToken == "Zrotation")
pNode.mChannels.push_back(Channel_RotationZ);
else
ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." );
ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
}
}
// ------------------------------------------------------------------------------------------------
// Reads the motion data
void BVHLoader::ReadMotion( aiScene* /*pScene*/)
{
void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
// Read number of frames
std::string tokenFrames = GetNextToken();
if( tokenFrames != "Frames:")
ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
if (tokenFrames != "Frames:")
ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int) numFramesFloat;
mAnimNumFrames = (unsigned int)numFramesFloat;
// Read frame duration
std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken();
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." );
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
mAnimTickDuration = GetNextTokenAsFloat();
// resize value vectors for each node
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames);
// now read all the data and store it in the corresponding node's value vector
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
{
for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) {
// on each line read the values for all nodes
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
{
for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) {
// get as many values as the node has channels
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
it->mChannelValues.push_back( GetNextTokenAsFloat());
for (unsigned int c = 0; c < it->mChannels.size(); ++c)
it->mChannelValues.push_back(GetNextTokenAsFloat());
}
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
@ -374,16 +349,14 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
// ------------------------------------------------------------------------------------------------
// Retrieves the next token
std::string BVHLoader::GetNextToken()
{
std::string BVHLoader::GetNextToken() {
// skip any preceding whitespace
while( mReader != mBuffer.end())
{
if( !isspace( *mReader))
while (mReader != mBuffer.end()) {
if (!isspace(*mReader))
break;
// count lines
if( *mReader == '\n')
if (*mReader == '\n')
mLine++;
++mReader;
@ -391,16 +364,15 @@ std::string BVHLoader::GetNextToken()
// collect all chars till the next whitespace. BVH is easy in respect to that.
std::string token;
while( mReader != mBuffer.end())
{
if( isspace( *mReader))
while (mReader != mBuffer.end()) {
if (isspace(*mReader))
break;
token.push_back( *mReader);
token.push_back(*mReader);
++mReader;
// little extra logic to make sure braces are counted correctly
if( token == "{" || token == "}")
if (token == "{" || token == "}")
break;
}
@ -410,111 +382,101 @@ std::string BVHLoader::GetNextToken()
// ------------------------------------------------------------------------------------------------
// Reads the next token as a float
float BVHLoader::GetNextTokenAsFloat()
{
float BVHLoader::GetNextTokenAsFloat() {
std::string token = GetNextToken();
if( token.empty())
ThrowException( "Unexpected end of file while trying to read a float");
if (token.empty())
ThrowException("Unexpected end of file while trying to read a float");
// check if the float is valid by testing if the atof() function consumed every char of the token
const char* ctoken = token.c_str();
const char *ctoken = token.c_str();
float result = 0.0f;
ctoken = fast_atoreal_move<float>( ctoken, result);
ctoken = fast_atoreal_move<float>(ctoken, result);
if( ctoken != token.c_str() + token.length())
ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." );
if (ctoken != token.c_str() + token.length())
ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
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);
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
void BVHLoader::CreateAnimation( aiScene* pScene)
{
void BVHLoader::CreateAnimation(aiScene *pScene) {
// create the animation
pScene->mNumAnimations = 1;
pScene->mAnimations = new aiAnimation*[1];
aiAnimation* anim = new aiAnimation;
pScene->mAnimations = new aiAnimation *[1];
aiAnimation *anim = new aiAnimation;
pScene->mAnimations[0] = anim;
// put down the basic parameters
anim->mName.Set( "Motion");
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
anim->mDuration = double( mAnimNumFrames - 1);
anim->mName.Set("Motion");
anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration);
anim->mDuration = double(mAnimNumFrames - 1);
// now generate the tracks for all nodes
anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
for (unsigned int i = 0; i < anim->mNumChannels;++i)
anim->mChannels[i] = NULL;
// FIX: set the array elements to nullptr to ensure proper deletion if an exception is thrown
for (unsigned int i = 0; i < anim->mNumChannels; ++i)
anim->mChannels[i] = nullptr;
for( unsigned int a = 0; a < anim->mNumChannels; a++)
{
const Node& node = mNodes[a];
const std::string nodeName = std::string( node.mNode->mName.data );
aiNodeAnim* nodeAnim = new aiNodeAnim;
for (unsigned int a = 0; a < anim->mNumChannels; a++) {
const Node &node = mNodes[a];
const std::string nodeName = std::string(node.mNode->mName.data);
aiNodeAnim *nodeAnim = new aiNodeAnim;
anim->mChannels[a] = nodeAnim;
nodeAnim->mNodeName.Set( nodeName);
std::map<BVHLoader::ChannelType, int> channelMap;
nodeAnim->mNodeName.Set(nodeName);
std::map<BVHLoader::ChannelType, int> channelMap;
//Build map of channels
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
{
channelMap[node.mChannels[channel]] = channel;
}
//Build map of channels
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
channelMap[node.mChannels[channel]] = channel;
}
// translational part, if given
if( node.mChannels.size() == 6)
{
if (node.mChannels.size() == 6) {
nodeAnim->mNumPositionKeys = mAnimNumFrames;
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
aiVectorKey* poskey = nodeAnim->mPositionKeys;
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
{
poskey->mTime = double( fr);
aiVectorKey *poskey = nodeAnim->mPositionKeys;
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
poskey->mTime = double(fr);
// Now compute all translations
for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
{
//Find channel in node
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
// Now compute all translations
for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
//Find channel in node
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
if (mapIter == channelMap.end())
throw DeadlyImportError("Missing position channel in node " + nodeName);
else {
int channelIdx = mapIter->second;
switch (channel) {
case Channel_PositionX:
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionY:
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionZ:
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
default:
break;
}
if (mapIter == channelMap.end())
throw DeadlyImportError("Missing position channel in node " + nodeName);
else {
int channelIdx = mapIter->second;
switch (channel) {
case Channel_PositionX:
poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionY:
poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
case Channel_PositionZ:
poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
break;
}
default:
break;
}
}
}
++poskey;
}
} else
{
} else {
// if no translation part is given, put a default sequence
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
nodeAnim->mNumPositionKeys = 1;
nodeAnim->mPositionKeys = new aiVectorKey[1];
nodeAnim->mPositionKeys[0].mTime = 0.0;
@ -527,42 +489,36 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
// Then create the number of rotation keys
nodeAnim->mNumRotationKeys = mAnimNumFrames;
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
{
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
aiMatrix4x4 temp;
aiMatrix3x3 rotMatrix;
for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
{
//Find channel in node
std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
if (mapIter == channelMap.end())
throw DeadlyImportError("Missing rotation channel in node " + nodeName);
else {
int channelIdx = mapIter->second;
// translate ZXY euler angels into a quaternion
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
// Compute rotation transformations in the right order
switch (channel)
{
case Channel_RotationX:
aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp);
break;
case Channel_RotationY:
aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);
break;
case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp);
break;
default:
break;
}
for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) {
switch (node.mChannels[channelIdx]) {
case Channel_RotationX:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
case Channel_RotationY:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
case Channel_RotationZ:
{
const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
}
break;
default:
break;
}
}
rotkey->mTime = double( fr);
rotkey->mValue = aiQuaternion( rotMatrix);
}
rotkey->mTime = double(fr);
rotkey->mValue = aiQuaternion(rotMatrix);
++rotkey;
}
}
@ -572,7 +528,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
nodeAnim->mNumScalingKeys = 1;
nodeAnim->mScalingKeys = new aiVectorKey[1];
nodeAnim->mScalingKeys[0].mTime = 0.0;
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f);
}
}
}

View File

@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiNode;
namespace Assimp
{
namespace Assimp {
// --------------------------------------------------------------------------------
/** Loader class to read Motion Capturing data from a .bvh file.
@ -63,12 +62,10 @@ namespace Assimp
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
* inside the loader just to be able to see something.
*/
class BVHLoader : public BaseImporter
{
class BVHLoader : public BaseImporter {
/** Possible animation channels for which the motion data holds the values */
enum ChannelType
{
enum ChannelType {
Channel_PositionX,
Channel_PositionY,
Channel_PositionZ,
@ -78,61 +75,57 @@ class BVHLoader : public BaseImporter
};
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
struct Node
{
const aiNode* mNode;
struct Node {
const aiNode *mNode;
std::vector<ChannelType> mChannels;
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
Node()
: mNode(nullptr)
{ }
Node() :
mNode(nullptr) {}
explicit Node( const aiNode* pNode) : mNode( pNode) { }
explicit Node(const aiNode *pNode) :
mNode(pNode) {}
};
public:
BVHLoader();
~BVHLoader();
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const;
void SetupProperties(const Importer* pImp);
const aiImporterDesc* GetInfo () const;
void SetupProperties(const Importer *pImp);
const aiImporterDesc *GetInfo() const;
protected:
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
protected:
/** Reads the file */
void ReadStructure( aiScene* pScene);
void ReadStructure(aiScene *pScene);
/** Reads the hierarchy */
void ReadHierarchy( aiScene* pScene);
void ReadHierarchy(aiScene *pScene);
/** 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. */
aiNode* ReadEndSite( const std::string& pParentName);
aiNode *ReadEndSite(const std::string &pParentName);
/** Reads a node offset for the given node */
void ReadNodeOffset( aiNode* pNode);
void ReadNodeOffset(aiNode *pNode);
/** Reads the animation channels into the given node */
void ReadNodeChannels( BVHLoader::Node& pNode);
void ReadNodeChannels(BVHLoader::Node &pNode);
/** Reads the motion data */
void ReadMotion( aiScene* pScene);
void ReadMotion(aiScene *pScene);
/** Retrieves the next token */
std::string GetNextToken();
@ -141,10 +134,10 @@ protected:
float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
/** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation( aiScene* pScene);
void CreateAnimation(aiScene *pScene);
protected:
/** Filename, for a verbose error message */

View File

@ -42,165 +42,143 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Conversion of Blender's new BMesh stuff
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderBMesh.h"
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderBMesh.h"
#include "BlenderTessellator.h"
namespace Assimp
{
template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
{
static auto prefix = "BLEND_BMESH: ";
return prefix;
}
namespace Assimp {
template <>
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
static auto prefix = "BLEND_BMESH: ";
return prefix;
}
} // namespace Assimp
using namespace Assimp;
using namespace Assimp::Blender;
using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
BMesh( mesh ),
triMesh( NULL )
{
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
BMesh(mesh),
triMesh(nullptr) {
ai_assert(nullptr != mesh);
}
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::~BlenderBMeshConverter( )
{
DestroyTriMesh( );
BlenderBMeshConverter::~BlenderBMeshConverter() {
DestroyTriMesh();
}
// ------------------------------------------------------------------------------------------------
bool BlenderBMeshConverter::ContainsBMesh( ) const
{
bool BlenderBMeshConverter::ContainsBMesh() const {
// TODO - Should probably do some additional verification here
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
}
// ------------------------------------------------------------------------------------------------
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
{
AssertValidMesh( );
AssertValidSizes( );
PrepareTriMesh( );
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
AssertValidMesh();
AssertValidSizes();
PrepareTriMesh();
for ( int i = 0; i < BMesh->totpoly; ++i )
{
const MPoly& poly = BMesh->mpoly[ i ];
ConvertPolyToFaces( poly );
for (int i = 0; i < BMesh->totpoly; ++i) {
const MPoly &poly = BMesh->mpoly[i];
ConvertPolyToFaces(poly);
}
return triMesh;
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidMesh( )
{
if ( !ContainsBMesh( ) )
{
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
void BlenderBMeshConverter::AssertValidMesh() {
if (!ContainsBMesh()) {
ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidSizes( )
{
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
{
ThrowException( "BMesh poly array has incorrect size" );
void BlenderBMeshConverter::AssertValidSizes() {
if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
ThrowException("BMesh poly array has incorrect size");
}
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
{
ThrowException( "BMesh loop array has incorrect size" );
if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
ThrowException("BMesh loop array has incorrect size");
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::PrepareTriMesh( )
{
if ( triMesh )
{
DestroyTriMesh( );
void BlenderBMeshConverter::PrepareTriMesh() {
if (triMesh) {
DestroyTriMesh();
}
triMesh = new Mesh( *BMesh );
triMesh = new Mesh(*BMesh);
triMesh->totface = 0;
triMesh->mface.clear( );
triMesh->mface.clear();
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::DestroyTriMesh( )
{
void BlenderBMeshConverter::DestroyTriMesh() {
delete triMesh;
triMesh = NULL;
triMesh = nullptr;
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
{
const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
if ( poly.totloop == 3 || poly.totloop == 4 )
{
AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
if (poly.totloop == 3 || poly.totloop == 4) {
AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0);
// UVs are optional, so only convert when present.
if ( BMesh->mloopuv.size() )
{
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
{
ThrowException( "BMesh uv loop array has incorrect size" );
if (BMesh->mloopuv.size()) {
if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
ThrowException("BMesh uv loop array has incorrect size");
}
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
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
BlenderTessellatorGL tessGL( *this );
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
BlenderTessellatorGL tessGL(*this);
tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
BlenderTessellatorP2T tessP2T( *this );
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
BlenderTessellatorP2T tessP2T(*this);
tessP2T.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
#endif
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
{
void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
MFace face;
face.v1 = v1;
face.v2 = v2;
face.v3 = v3;
face.v4 = v4;
face.flag = 0;
// TODO - Work out how materials work
face.mat_nr = 0;
triMesh->mface.push_back( face );
triMesh->totface = static_cast<int>(triMesh->mface.size( ));
triMesh->mface.push_back(face);
triMesh->totface = static_cast<int>(triMesh->mface.size());
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
{
void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) {
MTFace mtface;
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
if ( uv4 )
{
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
if (uv4) {
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
}
triMesh->mtface.push_back( mtface );
triMesh->mtface.push_back(mtface);
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -0,0 +1,181 @@
#include "BlenderCustomData.h"
#include "BlenderDNA.h"
#include <array>
#include <functional>
namespace Assimp {
namespace Blender {
/**
* @brief read/convert of Structure array to memory
*/
template <typename T>
bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
for (size_t i = 0; i < cnt; ++i) {
T read;
s.Convert(read, db);
*p = read;
p++;
}
return true;
}
/**
* @brief pointer to function read memory for n CustomData types
*/
typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db);
typedef ElemBase *(*PCreate)(const size_t cnt);
typedef void (*PDestroy)(ElemBase *);
#define IMPL_STRUCT_READ(ty) \
bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
ty *ptr = dynamic_cast<ty *>(v); \
if (nullptr == ptr) { \
return false; \
} \
return read<ty>(db.dna[#ty], ptr, cnt, db); \
}
#define IMPL_STRUCT_CREATE(ty) \
ElemBase *create##ty(const size_t cnt) { \
return new ty[cnt]; \
}
#define IMPL_STRUCT_DESTROY(ty) \
void destroy##ty(ElemBase *pE) { \
ty *p = dynamic_cast<ty *>(pE); \
delete[] p; \
}
/**
* @brief helper macro to define Structure functions
*/
#define IMPL_STRUCT(ty) \
IMPL_STRUCT_READ(ty) \
IMPL_STRUCT_CREATE(ty) \
IMPL_STRUCT_DESTROY(ty)
// supported structures for CustomData
IMPL_STRUCT(MVert)
IMPL_STRUCT(MEdge)
IMPL_STRUCT(MFace)
IMPL_STRUCT(MTFace)
IMPL_STRUCT(MTexPoly)
IMPL_STRUCT(MLoopUV)
IMPL_STRUCT(MLoopCol)
IMPL_STRUCT(MPoly)
IMPL_STRUCT(MLoop)
/**
* @brief describes the size of data and the read function to be used for single CustomerData.type
*/
struct CustomDataTypeDescription {
PRead Read; ///< function to read one CustomData type element
PCreate Create; ///< function to allocate n type elements
PDestroy Destroy;
CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) :
Read(read), Create(create), Destroy(destroy) {}
};
/**
* @brief helper macro to define Structure type specific CustomDataTypeDescription
* @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function
*/
#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \
CustomDataTypeDescription { &read##ty, &create##ty, &destroy##ty }
/**
* @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type
*/
#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \
CustomDataTypeDescription { nullptr, nullptr, nullptr }
/**
* @brief descriptors for data pointed to from CustomDataLayer.data
* @note some of the CustomData uses already well defined Structures
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
* use a special readfunction for that cases
*/
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION } };
bool isValidCustomDataType(const int cdtype) {
return cdtype >= 0 && cdtype < CD_NUMTYPES;
}
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) {
throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
}
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
// allocate cnt elements and parse them from file
out.reset(cdtd.Create(cnt), cdtd.Destroy);
return cdtd.Read(out.get(), cnt, db);
}
return false;
}
std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
if (it->get()->type == cdtype && name == it->get()->name) {
return *it;
}
}
return nullptr;
}
const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
if (pLayer && pLayer->data) {
return pLayer->data.get();
}
return nullptr;
}
} // namespace Blender
} // namespace Assimp

View File

@ -45,25 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* serialized set of data structures.
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include <assimp/StreamReader.h>
#include <assimp/fast_atof.h>
#include <assimp/TinyFormatter.h>
#include <assimp/fast_atof.h>
using namespace Assimp;
using namespace Assimp::Blender;
using namespace Assimp::Formatter;
static bool match4(StreamReaderAny& stream, const char* string) {
ai_assert( nullptr != string );
static bool match4(StreamReaderAny &stream, const char *string) {
ai_assert(nullptr != string);
char tmp[4];
tmp[ 0 ] = ( stream ).GetI1();
tmp[ 1 ] = ( stream ).GetI1();
tmp[ 2 ] = ( stream ).GetI1();
tmp[ 3 ] = ( stream ).GetI1();
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
tmp[0] = (stream).GetI1();
tmp[1] = (stream).GetI1();
tmp[2] = (stream).GetI1();
tmp[3] = (stream).GetI1();
return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]);
}
struct Type {
@ -72,75 +71,76 @@ struct Type {
};
// ------------------------------------------------------------------------------------------------
void DNAParser::Parse ()
{
StreamReaderAny& stream = *db.reader.get();
DNA& dna = db.dna;
void DNAParser::Parse() {
StreamReaderAny &stream = *db.reader.get();
DNA &dna = db.dna;
if(!match4(stream,"SDNA")) {
if (!match4(stream, "SDNA")) {
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
}
// name dictionary
if(!match4(stream,"NAME")) {
if (!match4(stream, "NAME")) {
throw DeadlyImportError("BlenderDNA: Expected NAME field");
}
std::vector<std::string> names (stream.GetI4());
for(std::string& s : names) {
std::vector<std::string> names(stream.GetI4());
for (std::string &s : names) {
while (char c = stream.GetI1()) {
s += c;
}
}
// type dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"TYPE")) {
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "TYPE")) {
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
}
std::vector<Type> types (stream.GetI4());
for(Type& s : types) {
std::vector<Type> types(stream.GetI4());
for (Type &s : types) {
while (char c = stream.GetI1()) {
s.name += c;
}
}
// type length dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"TLEN")) {
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "TLEN")) {
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
}
for(Type& s : types) {
for (Type &s : types) {
s.size = stream.GetI2();
}
// structures dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"STRC")) {
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
;
if (!match4(stream, "STRC")) {
throw DeadlyImportError("BlenderDNA: Expected STRC field");
}
size_t end = stream.GetI4(), fields = 0;
dna.structures.reserve(end);
for(size_t i = 0; i != end; ++i) {
for (size_t i = 0; i != end; ++i) {
uint16_t n = stream.GetI2();
if (n >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure name" ,n,
" (there are only ", types.size(), " entries)"
));
"BlenderDNA: Invalid type index in structure name", n,
" (there are only ", types.size(), " entries)"));
}
// maintain separate indexes
dna.indices[types[n].name] = dna.structures.size();
dna.structures.push_back(Structure());
Structure& s = dna.structures.back();
s.name = types[n].name;
Structure &s = dna.structures.back();
s.name = types[n].name;
//s.index = dna.structures.size()-1;
n = stream.GetI2();
@ -152,12 +152,11 @@ void DNAParser::Parse ()
uint16_t j = stream.GetI2();
if (j >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"
));
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"));
}
s.fields.push_back(Field());
Field& f = s.fields.back();
Field &f = s.fields.back();
f.offset = offset;
f.type = types[j].name;
@ -166,9 +165,8 @@ void DNAParser::Parse ()
j = stream.GetI2();
if (j >= names.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"
));
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"));
}
f.name = names[j];
@ -191,26 +189,25 @@ void DNAParser::Parse ()
const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) {
throw DeadlyImportError((format(),
"BlenderDNA: Encountered invalid array declaration ",
f.name
));
"BlenderDNA: Encountered invalid array declaration ",
f.name));
}
f.flags |= FieldFlag_Array;
DNA::ExtractArraySize(f.name,f.array_sizes);
f.name = f.name.substr(0,rb);
DNA::ExtractArraySize(f.name, f.array_sizes);
f.name = f.name.substr(0, rb);
f.size *= f.array_sizes[0] * f.array_sizes[1];
}
// maintain separate indexes
s.indices[f.name] = s.fields.size()-1;
s.indices[f.name] = s.fields.size() - 1;
offset += f.size;
}
s.size = offset;
}
ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
dna.DumpToFile();
@ -220,13 +217,11 @@ void DNAParser::Parse ()
dna.RegisterConverters();
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
#include <fstream>
// ------------------------------------------------------------------------------------------------
void DNA :: DumpToFile()
{
void DNA ::DumpToFile() {
// we don't bother using the VFS here for this is only for debugging.
// (and all your bases are belong to us).
@ -235,12 +230,14 @@ void DNA :: DumpToFile()
ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
return;
}
f << "Field format: type name offset size" << "\n";
f << "Structure format: name size" << "\n";
f << "Field format: type name offset size"
<< "\n";
f << "Structure format: name size"
<< "\n";
for(const Structure& s : structures) {
for (const Structure &s : structures) {
f << s.name << " " << s.size << "\n\n";
for(const Field& ff : s.fields) {
for (const Field &ff : s.fields) {
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
}
f << "\n";
@ -252,11 +249,9 @@ void DNA :: DumpToFile()
#endif
// ------------------------------------------------------------------------------------------------
/*static*/ void DNA :: ExtractArraySize(
const std::string& out,
size_t array_sizes[2]
)
{
/*static*/ void DNA ::ExtractArraySize(
const std::string &out,
size_t array_sizes[2]) {
array_sizes[0] = array_sizes[1] = 1;
std::string::size_type pos = out.find('[');
if (pos++ == std::string::npos) {
@ -264,7 +259,7 @@ void DNA :: DumpToFile()
}
array_sizes[0] = strtoul10(&out[pos]);
pos = out.find('[',pos);
pos = out.find('[', pos);
if (pos++ == std::string::npos) {
return;
}
@ -272,36 +267,32 @@ void DNA :: DumpToFile()
}
// ------------------------------------------------------------------------------------------------
std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
const Structure& structure,
const FileDatabase& db
) const
{
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
const Structure &structure,
const FileDatabase &db) const {
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
if (it == converters.end()) {
return std::shared_ptr< ElemBase >();
return std::shared_ptr<ElemBase>();
}
std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
(structure.*((*it).second.second))(ret,db);
std::shared_ptr<ElemBase> ret = (structure.*((*it).second.first))();
(structure.*((*it).second.second))(ret, db);
return ret;
}
// ------------------------------------------------------------------------------------------------
DNA::FactoryPair DNA :: GetBlobToStructureConverter(
const Structure& structure,
const FileDatabase& /*db*/
) const
{
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
const Structure &structure,
const FileDatabase & /*db*/
) const {
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
return it == converters.end() ? FactoryPair() : (*it).second;
}
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
// ------------------------------------------------------------------------------------------------
void DNA :: AddPrimitiveStructures()
{
void DNA ::AddPrimitiveStructures() {
// NOTE: these are just dummies. Their presence enforces
// Structure::Convert<target_type> to be called on these
// empty structures. These converters are special
@ -311,30 +302,27 @@ void DNA :: AddPrimitiveStructures()
// in question.
indices["int"] = structures.size();
structures.push_back( Structure() );
structures.push_back(Structure());
structures.back().name = "int";
structures.back().size = 4;
indices["short"] = structures.size();
structures.push_back( Structure() );
structures.push_back(Structure());
structures.back().name = "short";
structures.back().size = 2;
indices["char"] = structures.size();
structures.push_back( Structure() );
structures.push_back(Structure());
structures.back().name = "char";
structures.back().size = 1;
indices["float"] = structures.size();
structures.push_back( Structure() );
structures.push_back(Structure());
structures.back().name = "float";
structures.back().size = 4;
indices["double"] = structures.size();
structures.push_back( Structure() );
structures.push_back(Structure());
structures.back().name = "double";
structures.back().size = 8;
@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
}
// ------------------------------------------------------------------------------------------------
void SectionParser :: Next()
{
void SectionParser ::Next() {
stream.SetCurrentPos(current.start + current.size);
const char tmp[] = {
@ -352,7 +339,7 @@ void SectionParser :: Next()
(const 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);
current.size = stream.GetI4();
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
@ -366,10 +353,8 @@ void SectionParser :: Next()
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
ASSIMP_LOG_DEBUG(current.id);
ASSIMP_LOG_VERBOSE_DEBUG(current.id);
#endif
}
#endif

View File

@ -49,26 +49,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/BaseImporter.h>
#include <assimp/StreamReader.h>
#include <assimp/DefaultLogger.hpp>
#include <stdint.h>
#include <memory>
#include <assimp/DefaultLogger.hpp>
#include <map>
#include <memory>
// enable verbose log output. really verbose, so be careful.
#ifdef ASSIMP_BUILD_DEBUG
# define ASSIMP_BUILD_BLENDER_DEBUG
#define ASSIMP_BUILD_BLENDER_DEBUG
#endif
// #define ASSIMP_BUILD_BLENDER_NO_STATS
namespace Assimp {
namespace Assimp {
template <bool,bool> class StreamReader;
typedef StreamReader<true,true> StreamReaderAny;
template <bool, bool>
class StreamReader;
typedef StreamReader<true, true> StreamReaderAny;
namespace Blender {
class FileDatabase;
class FileDatabase;
struct FileBlockHead;
template <template <typename> class TOUT>
@ -82,8 +83,8 @@ class ObjectCache;
* ancestry. */
// -------------------------------------------------------------------------------
struct Error : DeadlyImportError {
Error (const std::string& s)
: DeadlyImportError(s) {
Error(const std::string &s) :
DeadlyImportError(s) {
// empty
}
};
@ -93,9 +94,8 @@ struct Error : DeadlyImportError {
* descendents. It serves as base class for all data structure fields. */
// -------------------------------------------------------------------------------
struct ElemBase {
ElemBase()
: dna_type(nullptr)
{
ElemBase() :
dna_type(nullptr) {
// empty
}
@ -110,7 +110,7 @@ struct ElemBase {
* data type is not static, i.e. a std::shared_ptr<ElemBase>
* in the scene description would have its type resolved
* at runtime, so this member is always set. */
const char* dna_type;
const char *dna_type;
};
// -------------------------------------------------------------------------------
@ -120,8 +120,8 @@ struct ElemBase {
* they used to point to.*/
// -------------------------------------------------------------------------------
struct Pointer {
Pointer()
: val() {
Pointer() :
val() {
// empty
}
uint64_t val;
@ -131,8 +131,8 @@ struct Pointer {
/** Represents a generic offset within a BLEND file */
// -------------------------------------------------------------------------------
struct FileOffset {
FileOffset()
: val() {
FileOffset() :
val() {
// empty
}
uint64_t val;
@ -154,7 +154,7 @@ public:
resize(0);
}
operator bool () const {
operator bool() const {
return !empty();
}
};
@ -164,7 +164,7 @@ public:
// -------------------------------------------------------------------------------
enum FieldFlags {
FieldFlag_Pointer = 0x1,
FieldFlag_Array = 0x2
FieldFlag_Array = 0x2
};
// -------------------------------------------------------------------------------
@ -200,7 +200,7 @@ enum ErrorPolicy {
};
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
# define ErrorPolicy_Igno ErrorPolicy_Warn
#define ErrorPolicy_Igno ErrorPolicy_Warn
#endif
// -------------------------------------------------------------------------------
@ -212,47 +212,42 @@ enum ErrorPolicy {
* meaningful contents. */
// -------------------------------------------------------------------------------
class Structure {
template <template <typename> class> friend class ObjectCache;
template <template <typename> class>
friend class ObjectCache;
public:
Structure()
: cache_idx(static_cast<size_t>(-1) ){
Structure() :
cache_idx(static_cast<size_t>(-1)) {
// empty
}
public:
// publicly accessible members
std::string name;
vector< Field > fields;
vector<Field> fields;
std::map<std::string, size_t> indices;
size_t size;
public:
// --------------------------------------------------------
/** Access a field of the structure by its canonical name. The pointer version
* returns NULL on failure while the reference version raises an import error. */
inline const Field& operator [] (const std::string& ss) const;
inline const Field* Get (const std::string& ss) const;
* returns nullptr on failure while the reference version raises an import error. */
inline const Field &operator[](const std::string &ss) const;
inline const Field *Get(const std::string &ss) const;
// --------------------------------------------------------
/** Access a field of the structure by its index */
inline const Field& operator [] (const size_t i) const;
inline const Field &operator[](const size_t i) const;
// --------------------------------------------------------
inline bool operator== (const Structure& other) const {
inline bool operator==(const Structure &other) const {
return name == other.name; // name is meant to be an unique identifier
}
// --------------------------------------------------------
inline bool operator!= (const Structure& other) const {
inline bool operator!=(const Structure &other) const {
return name != other.name;
}
public:
// --------------------------------------------------------
/** Try to read an instance of the structure from the stream
* and attempt to convert to `T`. This is done by
@ -260,54 +255,54 @@ public:
* a compiler complain is the result.
* @param dest Destination value to be written
* @param db File database, including input stream. */
template <typename T> void Convert (T& dest, const FileDatabase& db) const;
template <typename T>
void Convert(T &dest, const FileDatabase &db) const;
// --------------------------------------------------------
// generic converter
template <typename T>
void Convert(std::shared_ptr<ElemBase> in,const FileDatabase& db) const;
void Convert(std::shared_ptr<ElemBase> in, const FileDatabase &db) const;
// --------------------------------------------------------
// generic allocator
template <typename T> std::shared_ptr<ElemBase> Allocate() const;
template <typename T>
std::shared_ptr<ElemBase> Allocate() const;
// --------------------------------------------------------
// field parsing for 1d arrays
template <int error_policy, typename T, size_t M>
void ReadFieldArray(T (& out)[M], const char* name,
const FileDatabase& db) const;
void ReadFieldArray(T (&out)[M], const char *name,
const FileDatabase &db) const;
// --------------------------------------------------------
// field parsing for 2d arrays
template <int error_policy, typename T, size_t M, size_t N>
void ReadFieldArray2(T (& out)[M][N], const char* name,
const FileDatabase& db) const;
void ReadFieldArray2(T (&out)[M][N], const char *name,
const FileDatabase &db) const;
// --------------------------------------------------------
// field parsing for pointer or dynamic array types
// (std::shared_ptr)
// The return value indicates whether the data was already cached.
template <int error_policy, template <typename> class TOUT, typename T>
bool ReadFieldPtr(TOUT<T>& out, const char* name,
const FileDatabase& db,
bool non_recursive = false) const;
bool ReadFieldPtr(TOUT<T> &out, const char *name,
const FileDatabase &db,
bool non_recursive = false) const;
// --------------------------------------------------------
// field parsing for static arrays of pointer or dynamic
// array types (std::shared_ptr[])
// The return value indicates whether the data was already cached.
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
const FileDatabase& db) const;
bool ReadFieldPtr(TOUT<T> (&out)[N], const char *name,
const FileDatabase &db) const;
// --------------------------------------------------------
// field parsing for `normal` values
// The return value indicates whether the data was already cached.
template <int error_policy, typename T>
void ReadField(T& out, const char* name,
const FileDatabase& db) const;
void ReadField(T &out, const char *name,
const FileDatabase &db) const;
// --------------------------------------------------------
/**
@ -318,7 +313,7 @@ public:
* @return true when read was successful
*/
template <int error_policy, template <typename> class TOUT, typename T>
bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
bool ReadFieldPtrVector(vector<TOUT<T>> &out, const char *name, const FileDatabase &db) const;
/**
* @brief parses raw customdata
@ -329,42 +324,42 @@ public:
* @return true when read was successful
*/
template <int error_policy>
bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
bool ReadCustomDataPtr(std::shared_ptr<ElemBase> &out, int cdtype, const char *name, const FileDatabase &db) const;
private:
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(TOUT<T> &out, const Pointer &ptrval,
const FileDatabase &db, const Field &f,
bool non_recursive = false) const;
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f,
bool non_recursive = false) const;
bool ResolvePointer(vector<TOUT<T>> &out, const Pointer &ptrval,
const FileDatabase &db, const Field &f, bool) const;
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f, bool) const;
bool ResolvePointer(std::shared_ptr<FileOffset> &out, const Pointer &ptrval,
const FileDatabase &db, const Field &f, bool) const;
// --------------------------------------------------------
bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f, bool) const;
// --------------------------------------------------------
inline const FileBlockHead* LocateFileBlockForAddress(
const Pointer & ptrval,
const FileDatabase& db) const;
inline const FileBlockHead *LocateFileBlockForAddress(
const Pointer &ptrval,
const FileDatabase &db) const;
private:
// ------------------------------------------------------------------------------
template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
template <typename T>
T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
out = std::shared_ptr<T>(new T());
s = 1;
return out.get();
}
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
template <typename T>
T *_allocate(vector<T> &out, size_t &s) const {
out.resize(s);
return s ? &out.front() : NULL;
return s ? &out.front() : nullptr;
}
// --------------------------------------------------------
@ -372,14 +367,14 @@ private:
struct _defaultInitializer {
template <typename T, unsigned int N>
void operator ()(T (& out)[N], const char* = NULL) {
void operator()(T (&out)[N], const char * = nullptr) {
for (unsigned int i = 0; i < N; ++i) {
out[i] = T();
}
}
template <typename T, unsigned int N, unsigned int M>
void operator ()(T (& out)[N][M], const char* = NULL) {
void operator()(T (&out)[N][M], const char * = nullptr) {
for (unsigned int i = 0; i < N; ++i) {
for (unsigned int j = 0; j < M; ++j) {
out[i][j] = T();
@ -388,21 +383,21 @@ private:
}
template <typename T>
void operator ()(T& out, const char* = NULL) {
void operator()(T &out, const char * = nullptr) {
out = T();
}
};
private:
mutable size_t cache_idx;
};
// --------------------------------------------------------
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
template <>
struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
template <typename T>
void operator ()(T& out, const char* reason = "<add reason>") {
void operator()(T &out, const char *reason = "<add reason>") {
ASSIMP_LOG_WARN(reason);
// ... and let the show go on
@ -410,10 +405,11 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
}
};
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
template <>
struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
template <typename T>
void operator ()(T& /*out*/,const char* = "") {
void operator()(T & /*out*/, const char * = "") {
// obviously, it is crucial that _DefaultInitializer is used
// only from within a catch clause.
throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
@ -421,13 +417,12 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
};
// -------------------------------------------------------------------------------------------------------
template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
const Pointer & ptrval,
const FileDatabase& db,
const Field& f,
bool
) const;
template <>
inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
const Pointer &ptrval,
const FileDatabase &db,
const Field &f,
bool) const;
// -------------------------------------------------------------------------------
/** Represents the full data structure information for a single BLEND file.
@ -435,40 +430,34 @@ template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(st
* #DNAParser does the reading and represents currently the only place where
* DNA is altered.*/
// -------------------------------------------------------------------------------
class DNA
{
class DNA {
public:
typedef void (Structure::*ConvertProcPtr) (
std::shared_ptr<ElemBase> in,
const FileDatabase&
) const;
typedef void (Structure::*ConvertProcPtr)(
std::shared_ptr<ElemBase> in,
const FileDatabase &) const;
typedef std::shared_ptr<ElemBase> (
Structure::*AllocProcPtr) () const;
Structure::*AllocProcPtr)() const;
typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
public:
std::map<std::string, FactoryPair > converters;
vector<Structure > structures;
std::map<std::string, FactoryPair> converters;
vector<Structure> structures;
std::map<std::string, size_t> indices;
public:
// --------------------------------------------------------
/** Access a structure by its canonical name, the pointer version returns NULL on failure
/** Access a structure by its canonical name, the pointer version returns nullptr on failure
* while the reference version raises an error. */
inline const Structure& operator [] (const std::string& ss) const;
inline const Structure* Get (const std::string& ss) const;
inline const Structure &operator[](const std::string &ss) const;
inline const Structure *Get(const std::string &ss) const;
// --------------------------------------------------------
/** Access a structure by its index */
inline const Structure& operator [] (const size_t i) const;
inline const Structure &operator[](const size_t i) const;
public:
// --------------------------------------------------------
/** Add structure definitions for all the primitive types,
* i.e. integer, short, char, float */
@ -483,7 +472,6 @@ public:
* known at compile time (consier Object::data).*/
void RegisterConverters();
// --------------------------------------------------------
/** Take an input blob from the stream, interpret it according to
* a its structure name and convert it to the intermediate
@ -491,10 +479,9 @@ public:
* @param structure Destination structure definition
* @param db File database.
* @return A null pointer if no appropriate converter is available.*/
std::shared_ptr< ElemBase > ConvertBlobToStructure(
const Structure& structure,
const FileDatabase& db
) const;
std::shared_ptr<ElemBase> ConvertBlobToStructure(
const Structure &structure,
const FileDatabase &db) const;
// --------------------------------------------------------
/** Find a suitable conversion function for a given Structure.
@ -505,10 +492,8 @@ public:
* @param db File database.
* @return A null pointer in .first if no appropriate converter is available.*/
FactoryPair GetBlobToStructureConverter(
const Structure& structure,
const FileDatabase& db
) const;
const Structure &structure,
const FileDatabase &db) const;
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
// --------------------------------------------------------
@ -527,25 +512,29 @@ public:
* @throw DeadlyImportError if more than 2 dimensions are
* encountered. */
static void ExtractArraySize(
const std::string& out,
size_t array_sizes[2]
);
const std::string &out,
size_t array_sizes[2]);
};
// special converters for primitive types
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<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;
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<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;
// -------------------------------------------------------------------------------
/** Describes a master file block header. Each master file sections holds n
* elements of a certain SDNA structure (or otherwise unspecified data). */
// -------------------------------------------------------------------------------
struct FileBlockHead
{
struct FileBlockHead {
// points right after the header of the file block
StreamReaderAny::pos start;
@ -561,66 +550,55 @@ struct FileBlockHead
// number of structure instances to follow
size_t num;
// file blocks are sorted by address to quickly locate specific memory addresses
bool operator < (const FileBlockHead& o) const {
bool operator<(const FileBlockHead &o) const {
return address.val < o.address.val;
}
// for std::upper_bound
operator const Pointer& () const {
operator const Pointer &() const {
return address;
}
};
// for std::upper_bound
inline bool operator< (const Pointer& a, const Pointer& b) {
inline bool operator<(const Pointer &a, const Pointer &b) {
return a.val < b.val;
}
// -------------------------------------------------------------------------------
/** Utility to read all master file blocks in turn. */
// -------------------------------------------------------------------------------
class SectionParser
{
class SectionParser {
public:
// --------------------------------------------------------
/** @param stream Inout stream, must point to the
* first section in the file. Call Next() once
* to have it read.
* @param ptr64 Pointer size in file is 64 bits? */
SectionParser(StreamReaderAny& stream,bool ptr64)
: stream(stream)
, ptr64(ptr64)
{
SectionParser(StreamReaderAny &stream, bool ptr64) :
stream(stream), ptr64(ptr64) {
current.size = current.start = 0;
}
public:
// --------------------------------------------------------
const FileBlockHead& GetCurrent() const {
const FileBlockHead &GetCurrent() const {
return current;
}
public:
// --------------------------------------------------------
/** Advance to the next section.
* @throw DeadlyImportError if the last chunk was passed. */
void Next();
public:
FileBlockHead current;
StreamReaderAny& stream;
StreamReaderAny &stream;
bool ptr64;
};
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
// -------------------------------------------------------------------------------
/** Import statistics, i.e. number of file blocks read*/
@ -628,17 +606,13 @@ public:
class Statistics {
public:
Statistics ()
: fields_read ()
, pointers_resolved ()
, cache_hits ()
// , blocks_read ()
, cached_objects ()
{}
Statistics() :
fields_read(), pointers_resolved(), cache_hits()
// , blocks_read ()
,
cached_objects() {}
public:
/** total number of fields we read */
unsigned int fields_read;
@ -662,17 +636,13 @@ public:
* avoids circular references and avoids object duplication. */
// -------------------------------------------------------------------------------
template <template <typename> class TOUT>
class ObjectCache
{
class ObjectCache {
public:
typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
public:
ObjectCache(const FileDatabase& db)
: db(db)
{
ObjectCache(const FileDatabase &db) :
db(db) {
// currently there are only ~400 structure records per blend file.
// we read only a small part of them and don't cache objects
// which we don't need, so this should suffice.
@ -680,17 +650,17 @@ public:
}
public:
// --------------------------------------------------------
/** Check whether a specific item is in the cache.
* @param s Data type of the item
* @param out Output pointer. Unchanged if the
* cache doesn't know the item yet.
* @param ptr Item address to look for. */
template <typename T> void get (
const Structure& s,
TOUT<T>& out,
const Pointer& ptr) const;
template <typename T>
void get(
const Structure &s,
TOUT<T> &out,
const Pointer &ptr) const;
// --------------------------------------------------------
/** Add an item to the cache after the item has
@ -700,47 +670,44 @@ public:
* @param s Data type of the item
* @param out Item to insert into the cache
* @param ptr address (cache key) of the item. */
template <typename T> void set
(const Structure& s,
const TOUT<T>& out,
const Pointer& ptr);
template <typename T>
void set(const Structure &s,
const TOUT<T> &out,
const Pointer &ptr);
private:
mutable vector<StructureCache> caches;
const FileDatabase& db;
const FileDatabase &db;
};
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
template <> class ObjectCache<Blender::vector>
{
template <>
class ObjectCache<Blender::vector> {
public:
ObjectCache(const FileDatabase &) {}
ObjectCache(const FileDatabase&) {}
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
template <typename T>
void get(const Structure &, vector<T> &, const Pointer &) {}
template <typename T>
void set(const Structure &, const vector<T> &, const Pointer &) {}
};
#ifdef _MSC_VER
# pragma warning(disable:4355)
#pragma warning(disable : 4355)
#endif
// -------------------------------------------------------------------------------
/** Memory representation of a full BLEND file and all its dependencies. The
* output aiScene is constructed from an instance of this data structure. */
// -------------------------------------------------------------------------------
class FileDatabase
{
template <template <typename> class TOUT> friend class ObjectCache;
class FileDatabase {
template <template <typename> class TOUT>
friend class ObjectCache;
public:
FileDatabase()
: _cacheArrays(*this)
, _cache(*this)
, next_cache_idx()
{}
FileDatabase() :
_cacheArrays(*this), _cache(*this), next_cache_idx() {}
public:
// publicly accessible fields
@ -748,12 +715,11 @@ public:
bool little;
DNA dna;
std::shared_ptr< StreamReaderAny > reader;
vector< FileBlockHead > entries;
std::shared_ptr<StreamReaderAny> reader;
vector<FileBlockHead> entries;
public:
Statistics& stats() const {
Statistics &stats() const {
return _stats;
}
@ -762,18 +728,16 @@ public:
// arrays of objects are never cached because we can't easily
// ensure their proper destruction.
template <typename T>
ObjectCache<std::shared_ptr>& cache(std::shared_ptr<T>& /*in*/) const {
ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
return _cache;
}
template <typename T>
ObjectCache<vector>& cache(vector<T>& /*in*/) const {
ObjectCache<vector> &cache(vector<T> & /*in*/) const {
return _cacheArrays;
}
private:
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
mutable Statistics _stats;
#endif
@ -785,24 +749,20 @@ private:
};
#ifdef _MSC_VER
# pragma warning(default:4355)
#pragma warning(default : 4355)
#endif
// -------------------------------------------------------------------------------
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
// -------------------------------------------------------------------------------
class DNAParser
{
class DNAParser {
public:
/** Bind the parser to a empty DNA and an input stream */
DNAParser(FileDatabase& db)
: db(db)
{}
DNAParser(FileDatabase &db) :
db(db) {}
public:
// --------------------------------------------------------
/** Locate the DNA in the file and parse it. The input
* stream is expected to point to the beginning of the DN1
@ -811,18 +771,16 @@ public:
* @throw DeadlyImportError if the DNA cannot be read.
* @note The position of the stream pointer is undefined
* afterwards.*/
void Parse ();
void Parse();
public:
/** Obtain a reference to the extracted DNA information */
const Blender::DNA& GetDNA() const {
const Blender::DNA &GetDNA() const {
return db.dna;
}
private:
FileDatabase& db;
FileDatabase &db;
};
/**
@ -835,9 +793,8 @@ private:
*/
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
} // end Blend
} // end Assimp
} // namespace Blender
} // namespace Assimp
#include "BlenderDNA.inl"

View File

@ -4,7 +4,6 @@ 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,
@ -70,7 +69,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
const Field* Structure :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &fields[(*it).second];
return it == indices.end() ? nullptr : &fields[(*it).second];
}
//--------------------------------------------------------------------------------
@ -239,11 +238,13 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
try {
f = &(*this)[name];
#ifdef _DEBUG
// sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array"));
}
#endif // _DEBUG
db.reader->IncPtr(f->offset);
@ -795,7 +796,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
const Structure* DNA :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &structures[(*it).second];
return it == indices.end() ? nullptr : &structures[(*it).second];
}
//--------------------------------------------------------------------------------

View File

@ -68,7 +68,7 @@ static const fpCreateModifier creators[] = {
&god<BlenderModifier_Mirror>,
&god<BlenderModifier_Subdivision>,
NULL // sentinel
nullptr // sentinel
};
// ------------------------------------------------------------------------------------------------
@ -127,7 +127,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
cnt++;
curgod = NULL;
curgod = nullptr;
break;
}
}
@ -229,7 +229,7 @@ void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const
// Only reverse the winding order if an odd number of axes were mirrored.
if (xs * ys * zs < 0) {
for (unsigned int j = 0; j < mesh->mNumFaces; ++j ) {
for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
aiFace &face = mesh->mFaces[j];
for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
@ -267,18 +267,18 @@ void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data,
Subdivider::Algorithm algo;
switch (mir.subdivType) {
case SubsurfModifierData::TYPE_CatmullClarke:
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_CatmullClarke:
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_Simple:
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_Simple:
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
algo = Subdivider::CATMULL_CLARKE;
break;
default:
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
return;
default:
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
return;
};
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));

View File

@ -0,0 +1,838 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2020, ASSIMP Development 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 Development 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 BlenderScene.cpp
* @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderScene.h"
#include "BlenderCustomData.h"
#include "BlenderDNA.h"
#include "BlenderSceneGen.h"
using namespace Assimp;
using namespace Assimp::Blender;
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Object>(
Object &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat, "obmat", db);
ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv, "parentinv", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr, "parsubstr", db);
{
std::shared_ptr<Object> parent;
ReadFieldPtr<ErrorPolicy_Warn>(parent, "*parent", db);
dest.parent = parent.get();
}
ReadFieldPtr<ErrorPolicy_Warn>(dest.track, "*track", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy, "*proxy", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from, "*proxy_from", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group, "*proxy_group", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group, "*dup_group", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.data, "*data", db);
ReadField<ErrorPolicy_Igno>(dest.modifiers, "modifiers", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Group>(
Group &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Igno>(dest.layer, "layer", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject, "*gobject", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTex>(
MTex &dest,
const FileDatabase &db) const {
int temp_short = 0;
ReadField<ErrorPolicy_Igno>(temp_short, "mapto", db);
dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
int temp = 0;
ReadField<ErrorPolicy_Igno>(temp, "blendtype", db);
dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
ReadFieldPtr<ErrorPolicy_Igno>(dest.object, "*object", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tex, "*tex", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.uvname, "uvname", db);
ReadField<ErrorPolicy_Igno>(temp, "projx", db);
dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp, "projy", db);
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp, "projz", db);
dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(dest.mapping, "mapping", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs, "ofs", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.size, "size", db);
ReadField<ErrorPolicy_Igno>(dest.rot, "rot", db);
ReadField<ErrorPolicy_Igno>(dest.texflag, "texflag", db);
ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
ReadField<ErrorPolicy_Igno>(dest.pmapto, "pmapto", db);
ReadField<ErrorPolicy_Igno>(dest.pmaptoneg, "pmaptoneg", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
ReadField<ErrorPolicy_Igno>(dest.colspecfac, "colspecfac", db);
ReadField<ErrorPolicy_Igno>(dest.mirrfac, "mirrfac", db);
ReadField<ErrorPolicy_Igno>(dest.alphafac, "alphafac", db);
ReadField<ErrorPolicy_Igno>(dest.difffac, "difffac", db);
ReadField<ErrorPolicy_Igno>(dest.specfac, "specfac", db);
ReadField<ErrorPolicy_Igno>(dest.emitfac, "emitfac", db);
ReadField<ErrorPolicy_Igno>(dest.hardfac, "hardfac", db);
ReadField<ErrorPolicy_Igno>(dest.norfac, "norfac", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<TFace>(
TFace &dest,
const FileDatabase &db) const {
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.col, "col", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<SubsurfModifierData>(
SubsurfModifierData &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
ReadField<ErrorPolicy_Warn>(dest.subdivType, "subdivType", db);
ReadField<ErrorPolicy_Fail>(dest.levels, "levels", db);
ReadField<ErrorPolicy_Igno>(dest.renderLevels, "renderLevels", db);
ReadField<ErrorPolicy_Igno>(dest.flags, "flags", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MFace>(
MFace &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
ReadField<ErrorPolicy_Fail>(dest.v3, "v3", db);
ReadField<ErrorPolicy_Fail>(dest.v4, "v4", db);
ReadField<ErrorPolicy_Fail>(dest.mat_nr, "mat_nr", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Lamp>(
Lamp &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
ReadField<ErrorPolicy_Igno>(dest.flags, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
ReadField<ErrorPolicy_Igno>(dest.totex, "totex", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
ReadField<ErrorPolicy_Igno>(dest.energy, "energy", db);
ReadField<ErrorPolicy_Warn>(dest.dist, "dist", db);
ReadField<ErrorPolicy_Igno>(dest.spotsize, "spotsize", db);
ReadField<ErrorPolicy_Igno>(dest.spotblend, "spotblend", db);
ReadField<ErrorPolicy_Warn>(dest.constant_coefficient, "coeff_const", db);
ReadField<ErrorPolicy_Warn>(dest.linear_coefficient, "coeff_lin", db);
ReadField<ErrorPolicy_Warn>(dest.quadratic_coefficient, "coeff_quad", db);
ReadField<ErrorPolicy_Igno>(dest.att1, "att1", db);
ReadField<ErrorPolicy_Igno>(dest.att2, "att2", db);
ReadField<ErrorPolicy_Igno>(temp, "falloff_type", db);
dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
ReadField<ErrorPolicy_Igno>(dest.sun_brightness, "sun_brightness", db);
ReadField<ErrorPolicy_Igno>(dest.area_size, "area_size", db);
ReadField<ErrorPolicy_Igno>(dest.area_sizey, "area_sizey", db);
ReadField<ErrorPolicy_Igno>(dest.area_sizez, "area_sizez", db);
ReadField<ErrorPolicy_Igno>(dest.area_shape, "area_shape", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MDeformWeight>(
MDeformWeight &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.def_nr, "def_nr", db);
ReadField<ErrorPolicy_Fail>(dest.weight, "weight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<PackedFile>(
PackedFile &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Warn>(dest.size, "size", db);
ReadField<ErrorPolicy_Warn>(dest.seek, "seek", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.data, "*data", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Base>(
Base &dest,
const FileDatabase &db) const {
// note: as per https://github.com/assimp/assimp/issues/128,
// reading the Object linked list recursively is prone to stack overflow.
// This structure converter is therefore an hand-written exception that
// does it iteratively.
const int initial_pos = db.reader->GetCurrentPos();
std::pair<Base *, int> todo = std::make_pair(&dest, initial_pos);
for (;;) {
Base &cur_dest = *todo.first;
db.reader->SetCurrentPos(todo.second);
// we know that this is a double-linked, circular list which we never
// traverse backwards, so don't bother resolving the back links.
cur_dest.prev = nullptr;
ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object, "*object", db);
// the return value of ReadFieldPtr indicates whether the object
// was already cached. In this case, we don't need to resolve
// it again.
if (!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next, "*next", db, true) && cur_dest.next) {
todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
continue;
}
break;
}
db.reader->SetCurrentPos(initial_pos + size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTFace>(
MTFace &dest,
const FileDatabase &db) const {
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Material>(
Material &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
ReadField<ErrorPolicy_Warn>(dest.specr, "specr", db);
ReadField<ErrorPolicy_Warn>(dest.specg, "specg", db);
ReadField<ErrorPolicy_Warn>(dest.specb, "specb", db);
ReadField<ErrorPolicy_Igno>(dest.har, "har", db);
ReadField<ErrorPolicy_Warn>(dest.ambr, "ambr", db);
ReadField<ErrorPolicy_Warn>(dest.ambg, "ambg", db);
ReadField<ErrorPolicy_Warn>(dest.ambb, "ambb", db);
ReadField<ErrorPolicy_Igno>(dest.mirr, "mirr", db);
ReadField<ErrorPolicy_Igno>(dest.mirg, "mirg", db);
ReadField<ErrorPolicy_Igno>(dest.mirb, "mirb", db);
ReadField<ErrorPolicy_Warn>(dest.emit, "emit", db);
ReadField<ErrorPolicy_Igno>(dest.ray_mirror, "ray_mirror", db);
ReadField<ErrorPolicy_Warn>(dest.alpha, "alpha", db);
ReadField<ErrorPolicy_Igno>(dest.ref, "ref", db);
ReadField<ErrorPolicy_Igno>(dest.translucency, "translucency", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.roughness, "roughness", db);
ReadField<ErrorPolicy_Igno>(dest.darkness, "darkness", db);
ReadField<ErrorPolicy_Igno>(dest.refrac, "refrac", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.group, "*group", db);
ReadField<ErrorPolicy_Warn>(dest.diff_shader, "diff_shader", db);
ReadField<ErrorPolicy_Warn>(dest.spec_shader, "spec_shader", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex, "*mtex", db);
ReadField<ErrorPolicy_Igno>(dest.amb, "amb", db);
ReadField<ErrorPolicy_Igno>(dest.ang, "ang", db);
ReadField<ErrorPolicy_Igno>(dest.spectra, "spectra", db);
ReadField<ErrorPolicy_Igno>(dest.spec, "spec", db);
ReadField<ErrorPolicy_Igno>(dest.zoffs, "zoffs", db);
ReadField<ErrorPolicy_Igno>(dest.add, "add", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir, "fresnel_mir", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir_i, "fresnel_mir_i", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra, "fresnel_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra_i, "fresnel_tra_i", db);
ReadField<ErrorPolicy_Igno>(dest.filter, "filter", db);
ReadField<ErrorPolicy_Igno>(dest.tx_limit, "tx_limit", db);
ReadField<ErrorPolicy_Igno>(dest.tx_falloff, "tx_falloff", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_mir, "gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_tra, "gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_mir, "adapt_thresh_mir", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_tra, "adapt_thresh_tra", db);
ReadField<ErrorPolicy_Igno>(dest.aniso_gloss_mir, "aniso_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.dist_mir, "dist_mir", db);
ReadField<ErrorPolicy_Igno>(dest.hasize, "hasize", db);
ReadField<ErrorPolicy_Igno>(dest.flaresize, "flaresize", db);
ReadField<ErrorPolicy_Igno>(dest.subsize, "subsize", db);
ReadField<ErrorPolicy_Igno>(dest.flareboost, "flareboost", db);
ReadField<ErrorPolicy_Igno>(dest.strand_sta, "strand_sta", db);
ReadField<ErrorPolicy_Igno>(dest.strand_end, "strand_end", db);
ReadField<ErrorPolicy_Igno>(dest.strand_ease, "strand_ease", db);
ReadField<ErrorPolicy_Igno>(dest.strand_surfnor, "strand_surfnor", db);
ReadField<ErrorPolicy_Igno>(dest.strand_min, "strand_min", db);
ReadField<ErrorPolicy_Igno>(dest.strand_widthfade, "strand_widthfade", db);
ReadField<ErrorPolicy_Igno>(dest.sbias, "sbias", db);
ReadField<ErrorPolicy_Igno>(dest.lbias, "lbias", db);
ReadField<ErrorPolicy_Igno>(dest.shad_alpha, "shad_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.param, "param", db);
ReadField<ErrorPolicy_Igno>(dest.rms, "rms", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_col, "rampfac_col", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_spec, "rampfac_spec", db);
ReadField<ErrorPolicy_Igno>(dest.friction, "friction", db);
ReadField<ErrorPolicy_Igno>(dest.fh, "fh", db);
ReadField<ErrorPolicy_Igno>(dest.reflect, "reflect", db);
ReadField<ErrorPolicy_Igno>(dest.fhdist, "fhdist", db);
ReadField<ErrorPolicy_Igno>(dest.xyfrict, "xyfrict", db);
ReadField<ErrorPolicy_Igno>(dest.sss_radius, "sss_radius", db);
ReadField<ErrorPolicy_Igno>(dest.sss_col, "sss_col", db);
ReadField<ErrorPolicy_Igno>(dest.sss_error, "sss_error", db);
ReadField<ErrorPolicy_Igno>(dest.sss_scale, "sss_scale", db);
ReadField<ErrorPolicy_Igno>(dest.sss_ior, "sss_ior", db);
ReadField<ErrorPolicy_Igno>(dest.sss_colfac, "sss_colfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_texfac, "sss_texfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_front, "sss_front", db);
ReadField<ErrorPolicy_Igno>(dest.sss_back, "sss_back", db);
ReadField<ErrorPolicy_Igno>(dest.material_type, "material_type", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth, "ray_depth", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth_tra, "ray_depth_tra", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_mir, "samp_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_tra, "samp_gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fadeto_mir, "fadeto_mir", db);
ReadField<ErrorPolicy_Igno>(dest.shade_flag, "shade_flag", db);
ReadField<ErrorPolicy_Igno>(dest.flarec, "flarec", db);
ReadField<ErrorPolicy_Igno>(dest.starc, "starc", db);
ReadField<ErrorPolicy_Igno>(dest.linec, "linec", db);
ReadField<ErrorPolicy_Igno>(dest.ringc, "ringc", db);
ReadField<ErrorPolicy_Igno>(dest.pr_lamp, "pr_lamp", db);
ReadField<ErrorPolicy_Igno>(dest.pr_texture, "pr_texture", db);
ReadField<ErrorPolicy_Igno>(dest.ml_flag, "ml_flag", db);
ReadField<ErrorPolicy_Igno>(dest.diff_shader, "diff_shader", db);
ReadField<ErrorPolicy_Igno>(dest.spec_shader, "spec_shader", db);
ReadField<ErrorPolicy_Igno>(dest.texco, "texco", db);
ReadField<ErrorPolicy_Igno>(dest.mapto, "mapto", db);
ReadField<ErrorPolicy_Igno>(dest.ramp_show, "ramp_show", db);
ReadField<ErrorPolicy_Igno>(dest.pad3, "pad3", db);
ReadField<ErrorPolicy_Igno>(dest.dynamode, "dynamode", db);
ReadField<ErrorPolicy_Igno>(dest.pad2, "pad2", db);
ReadField<ErrorPolicy_Igno>(dest.sss_flag, "sss_flag", db);
ReadField<ErrorPolicy_Igno>(dest.sss_preset, "sss_preset", db);
ReadField<ErrorPolicy_Igno>(dest.shadowonly_flag, "shadowonly_flag", db);
ReadField<ErrorPolicy_Igno>(dest.index, "index", db);
ReadField<ErrorPolicy_Igno>(dest.vcol_alpha, "vcol_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.pad4, "pad4", db);
ReadField<ErrorPolicy_Igno>(dest.seed1, "seed1", db);
ReadField<ErrorPolicy_Igno>(dest.seed2, "seed2", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTexPoly>(
MTexPoly &dest,
const FileDatabase &db) const {
{
std::shared_ptr<Image> tpage;
ReadFieldPtr<ErrorPolicy_Igno>(tpage, "*tpage", db);
dest.tpage = tpage.get();
}
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.transp, "transp", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Mesh>(
Mesh &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Fail>(dest.totface, "totface", db);
ReadField<ErrorPolicy_Fail>(dest.totedge, "totedge", db);
ReadField<ErrorPolicy_Fail>(dest.totvert, "totvert", db);
ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
ReadField<ErrorPolicy_Igno>(dest.totpoly, "totpoly", db);
ReadField<ErrorPolicy_Igno>(dest.subdiv, "subdiv", db);
ReadField<ErrorPolicy_Igno>(dest.subdivr, "subdivr", db);
ReadField<ErrorPolicy_Igno>(dest.subsurftype, "subsurftype", db);
ReadField<ErrorPolicy_Igno>(dest.smoothresh, "smoothresh", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mface, "*mface", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface, "*mtface", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tface, "*tface", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert, "*mvert", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.medge, "*medge", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop, "*mloop", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv, "*mloopuv", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol, "*mloopcol", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly, "*mpoly", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly, "*mtpoly", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert, "*dvert", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol, "*mcol", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mat, "**mat", db);
ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MDeformVert>(
MDeformVert &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Warn>(dest.dw, "*dw", db);
ReadField<ErrorPolicy_Igno>(dest.totweight, "totweight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<World>(
World &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoopCol>(
MLoopCol &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.r, "r", db);
ReadField<ErrorPolicy_Igno>(dest.g, "g", db);
ReadField<ErrorPolicy_Igno>(dest.b, "b", db);
ReadField<ErrorPolicy_Igno>(dest.a, "a", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MVert>(
MVert &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
//ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MEdge>(
MEdge &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
ReadField<ErrorPolicy_Igno>(dest.crease, "crease", db);
ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoopUV>(
MLoopUV &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Igno>(dest.uv, "uv", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<GroupObject>(
GroupObject &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.ob, "*ob", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ListBase>(
ListBase &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.last, "*last", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MLoop>(
MLoop &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.v, "v", db);
ReadField<ErrorPolicy_Igno>(dest.e, "e", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ModifierData>(
ModifierData &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.prev, "*prev", db);
ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<ID>(
ID &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MCol>(
MCol &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.r, "r", db);
ReadField<ErrorPolicy_Fail>(dest.g, "g", db);
ReadField<ErrorPolicy_Fail>(dest.b, "b", db);
ReadField<ErrorPolicy_Fail>(dest.a, "a", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MPoly>(
MPoly &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Igno>(dest.loopstart, "loopstart", db);
ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
ReadField<ErrorPolicy_Igno>(dest.mat_nr, "mat_nr", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Scene>(
Scene &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Library>(
Library &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadFieldArray<ErrorPolicy_Fail>(dest.filename, "filename", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.parent, "*parent", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Tex>(
Tex &dest,
const FileDatabase &db) const {
short temp_short = 0;
ReadField<ErrorPolicy_Igno>(temp_short, "imaflag", db);
dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
int temp = 0;
ReadField<ErrorPolicy_Fail>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
ReadFieldPtr<ErrorPolicy_Warn>(dest.ima, "*ima", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Camera>(
Camera &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
int temp = 0;
ReadField<ErrorPolicy_Warn>(temp, "type", db);
dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
ReadField<ErrorPolicy_Warn>(temp, "flag", db);
dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
ReadField<ErrorPolicy_Warn>(dest.lens, "lens", db);
ReadField<ErrorPolicy_Warn>(dest.sensor_x, "sensor_x", db);
ReadField<ErrorPolicy_Igno>(dest.clipsta, "clipsta", db);
ReadField<ErrorPolicy_Igno>(dest.clipend, "clipend", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MirrorModifierData>(
MirrorModifierData &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob, "*mirror_ob", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<Image>(
Image &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadField<ErrorPolicy_Igno>(dest.ok, "ok", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.source, "source", db);
ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
ReadField<ErrorPolicy_Igno>(dest.pad1, "pad1", db);
ReadField<ErrorPolicy_Igno>(dest.lastframe, "lastframe", db);
ReadField<ErrorPolicy_Igno>(dest.tpageflag, "tpageflag", db);
ReadField<ErrorPolicy_Igno>(dest.totbind, "totbind", db);
ReadField<ErrorPolicy_Igno>(dest.xrep, "xrep", db);
ReadField<ErrorPolicy_Igno>(dest.yrep, "yrep", db);
ReadField<ErrorPolicy_Igno>(dest.twsta, "twsta", db);
ReadField<ErrorPolicy_Igno>(dest.twend, "twend", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile, "*packedfile", db);
ReadField<ErrorPolicy_Igno>(dest.lastupdate, "lastupdate", db);
ReadField<ErrorPolicy_Igno>(dest.lastused, "lastused", db);
ReadField<ErrorPolicy_Igno>(dest.animspeed, "animspeed", db);
ReadField<ErrorPolicy_Igno>(dest.gen_x, "gen_x", db);
ReadField<ErrorPolicy_Igno>(dest.gen_y, "gen_y", db);
ReadField<ErrorPolicy_Igno>(dest.gen_type, "gen_type", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CustomData>(
CustomData &dest,
const FileDatabase &db) const {
ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CustomDataLayer>(
CustomDataLayer &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
void DNA::RegisterConverters() {
converters["Object"] = DNA::FactoryPair(&Structure::Allocate<Object>, &Structure::Convert<Object>);
converters["Group"] = DNA::FactoryPair(&Structure::Allocate<Group>, &Structure::Convert<Group>);
converters["MTex"] = DNA::FactoryPair(&Structure::Allocate<MTex>, &Structure::Convert<MTex>);
converters["TFace"] = DNA::FactoryPair(&Structure::Allocate<TFace>, &Structure::Convert<TFace>);
converters["SubsurfModifierData"] = DNA::FactoryPair(&Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData>);
converters["MFace"] = DNA::FactoryPair(&Structure::Allocate<MFace>, &Structure::Convert<MFace>);
converters["Lamp"] = DNA::FactoryPair(&Structure::Allocate<Lamp>, &Structure::Convert<Lamp>);
converters["MDeformWeight"] = DNA::FactoryPair(&Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight>);
converters["PackedFile"] = DNA::FactoryPair(&Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile>);
converters["Base"] = DNA::FactoryPair(&Structure::Allocate<Base>, &Structure::Convert<Base>);
converters["MTFace"] = DNA::FactoryPair(&Structure::Allocate<MTFace>, &Structure::Convert<MTFace>);
converters["Material"] = DNA::FactoryPair(&Structure::Allocate<Material>, &Structure::Convert<Material>);
converters["MTexPoly"] = DNA::FactoryPair(&Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly>);
converters["Mesh"] = DNA::FactoryPair(&Structure::Allocate<Mesh>, &Structure::Convert<Mesh>);
converters["MDeformVert"] = DNA::FactoryPair(&Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert>);
converters["World"] = DNA::FactoryPair(&Structure::Allocate<World>, &Structure::Convert<World>);
converters["MLoopCol"] = DNA::FactoryPair(&Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol>);
converters["MVert"] = DNA::FactoryPair(&Structure::Allocate<MVert>, &Structure::Convert<MVert>);
converters["MEdge"] = DNA::FactoryPair(&Structure::Allocate<MEdge>, &Structure::Convert<MEdge>);
converters["MLoopUV"] = DNA::FactoryPair(&Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV>);
converters["GroupObject"] = DNA::FactoryPair(&Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject>);
converters["ListBase"] = DNA::FactoryPair(&Structure::Allocate<ListBase>, &Structure::Convert<ListBase>);
converters["MLoop"] = DNA::FactoryPair(&Structure::Allocate<MLoop>, &Structure::Convert<MLoop>);
converters["ModifierData"] = DNA::FactoryPair(&Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData>);
converters["ID"] = DNA::FactoryPair(&Structure::Allocate<ID>, &Structure::Convert<ID>);
converters["MCol"] = DNA::FactoryPair(&Structure::Allocate<MCol>, &Structure::Convert<MCol>);
converters["MPoly"] = DNA::FactoryPair(&Structure::Allocate<MPoly>, &Structure::Convert<MPoly>);
converters["Scene"] = DNA::FactoryPair(&Structure::Allocate<Scene>, &Structure::Convert<Scene>);
converters["Library"] = DNA::FactoryPair(&Structure::Allocate<Library>, &Structure::Convert<Library>);
converters["Tex"] = DNA::FactoryPair(&Structure::Allocate<Tex>, &Structure::Convert<Tex>);
converters["Camera"] = DNA::FactoryPair(&Structure::Allocate<Camera>, &Structure::Convert<Camera>);
converters["MirrorModifierData"] = DNA::FactoryPair(&Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData>);
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -48,14 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BlenderDNA.h"
namespace Assimp {
namespace Assimp {
namespace Blender {
// Minor parts of this file are extracts from blender data structures,
// declared in the ./source/blender/makesdna directory.
// Stuff that is not used by Assimp is commented.
// NOTE
// this file serves as input data to the `./scripts/genblenddna.py`
// script. This script generates the actual binding code to read a
@ -95,15 +94,15 @@ namespace Blender {
// warn if field is missing, substitute default value
#ifdef WARN
# undef WARN
#undef WARN
#endif
#define WARN
#define WARN
// fail the import if the field does not exist
#ifdef FAIL
# undef FAIL
#undef FAIL
#endif
#define FAIL
#define FAIL
struct Object;
struct MTex;
@ -117,7 +116,7 @@ static const size_t MaxNameLen = 1024;
// -------------------------------------------------------------------------------
struct ID : ElemBase {
char name[ MaxNameLen ] WARN;
char name[MaxNameLen] WARN;
short flag;
};
@ -127,17 +126,16 @@ struct ListBase : ElemBase {
std::shared_ptr<ElemBase> last;
};
// -------------------------------------------------------------------------------
struct PackedFile : ElemBase {
int size WARN;
int seek WARN;
std::shared_ptr< FileOffset > data WARN;
int size WARN;
int seek WARN;
std::shared_ptr<FileOffset> data WARN;
};
// -------------------------------------------------------------------------------
struct GroupObject : ElemBase {
std::shared_ptr<GroupObject> prev,next FAIL;
std::shared_ptr<GroupObject> prev, next FAIL;
std::shared_ptr<Object> ob;
};
@ -157,23 +155,20 @@ struct World : ElemBase {
// -------------------------------------------------------------------------------
struct MVert : ElemBase {
float co[3] FAIL;
float no[3] FAIL; // readed as short and divided through / 32767.f
float no[3] FAIL; // readed as short and divided through / 32767.f
char flag;
int mat_nr WARN;
int bweight;
MVert() : ElemBase()
, flag(0)
, mat_nr(0)
, bweight(0)
{}
MVert() :
ElemBase(), flag(0), mat_nr(0), bweight(0) {}
};
// -------------------------------------------------------------------------------
struct MEdge : ElemBase {
int v1, v2 FAIL;
char crease, bweight;
short flag;
int v1, v2 FAIL;
char crease, bweight;
short flag;
};
// -------------------------------------------------------------------------------
@ -190,7 +185,7 @@ struct MLoopUV : ElemBase {
// -------------------------------------------------------------------------------
// Note that red and blue are not swapped, as with MCol
struct MLoopCol : ElemBase {
unsigned char r, g, b, a;
unsigned char r, g, b, a;
};
// -------------------------------------------------------------------------------
@ -203,19 +198,19 @@ struct MPoly : ElemBase {
// -------------------------------------------------------------------------------
struct MTexPoly : ElemBase {
Image* tpage;
Image *tpage;
char flag, transp;
short mode, tile, pad;
};
// -------------------------------------------------------------------------------
struct MCol : ElemBase {
char r,g,b,a FAIL;
char r, g, b, a FAIL;
};
// -------------------------------------------------------------------------------
struct MFace : ElemBase {
int v1,v2,v3,v4 FAIL;
int v1, v2, v3, v4 FAIL;
int mat_nr FAIL;
char flag;
};
@ -232,13 +227,9 @@ struct TFace : ElemBase {
// -------------------------------------------------------------------------------
struct MTFace : ElemBase {
MTFace()
: flag(0)
, mode(0)
, tile(0)
, unwrap(0)
{
}
MTFace() :
flag(0), mode(0), tile(0), unwrap(0) {
}
float uv[4][2] FAIL;
char flag;
@ -250,31 +241,31 @@ struct MTFace : ElemBase {
};
// -------------------------------------------------------------------------------
struct MDeformWeight : ElemBase {
int def_nr FAIL;
float weight FAIL;
struct MDeformWeight : ElemBase {
int def_nr FAIL;
float weight FAIL;
};
// -------------------------------------------------------------------------------
struct MDeformVert : ElemBase {
struct MDeformVert : ElemBase {
vector<MDeformWeight> dw WARN;
int totweight;
};
// -------------------------------------------------------------------------------
#define MA_RAYMIRROR 0x40000
#define MA_RAYMIRROR 0x40000
#define MA_TRANSPARENCY 0x10000
#define MA_RAYTRANSP 0x20000
#define MA_ZTRANSP 0x00040
#define MA_RAYTRANSP 0x20000
#define MA_ZTRANSP 0x00040
struct Material : ElemBase {
ID id FAIL;
float r,g,b WARN;
float specr,specg,specb WARN;
float r, g, b WARN;
float specr, specg, specb WARN;
short har;
float ambr,ambg,ambb WARN;
float mirr,mirg,mirb;
float ambr, ambg, ambb WARN;
float mirr, mirg, mirb;
float emit WARN;
float ray_mirror;
float alpha WARN;
@ -399,20 +390,19 @@ struct CustomDataLayer : ElemBase {
int active_mask;
int uid;
char name[64];
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
CustomDataLayer()
: ElemBase()
, type(0)
, offset(0)
, flag(0)
, active(0)
, active_rnd(0)
, active_clone(0)
, active_mask(0)
, uid(0)
, data(nullptr)
{
CustomDataLayer() :
ElemBase(),
type(0),
offset(0),
flag(0),
active(0),
active_rnd(0),
active_clone(0),
active_mask(0),
uid(0),
data(nullptr) {
memset(name, 0, sizeof name);
}
};
@ -430,8 +420,8 @@ CustomData 208
CustomDataExternal *external 200 8
*/
struct CustomData : ElemBase {
vector<std::shared_ptr<struct CustomDataLayer> > layers;
int typemap[42]; // CD_NUMTYPES
vector<std::shared_ptr<struct CustomDataLayer>> layers;
int typemap[42]; // CD_NUMTYPES
int totlayer;
int maxlayer;
int totsize;
@ -469,7 +459,7 @@ struct Mesh : ElemBase {
vector<MDeformVert> dvert;
vector<MCol> mcol;
vector< std::shared_ptr<Material> > mat FAIL;
vector<std::shared_ptr<Material>> mat FAIL;
struct CustomData vdata;
struct CustomData edata;
@ -490,142 +480,141 @@ struct Library : ElemBase {
// -------------------------------------------------------------------------------
struct Camera : ElemBase {
enum Type {
Type_PERSP = 0
,Type_ORTHO = 1
Type_PERSP = 0,
Type_ORTHO = 1
};
ID id FAIL;
Type type,flag WARN;
Type type, flag WARN;
float lens WARN;
float sensor_x WARN;
float clipsta, clipend;
};
// -------------------------------------------------------------------------------
struct Lamp : ElemBase {
enum FalloffType {
FalloffType_Constant = 0x0
,FalloffType_InvLinear = 0x1
,FalloffType_InvSquare = 0x2
FalloffType_Constant = 0x0,
FalloffType_InvLinear = 0x1,
FalloffType_InvSquare = 0x2
//,FalloffType_Curve = 0x3
//,FalloffType_Sliders = 0x4
};
enum Type {
Type_Local = 0x0
,Type_Sun = 0x1
,Type_Spot = 0x2
,Type_Hemi = 0x3
,Type_Area = 0x4
Type_Local = 0x0,
Type_Sun = 0x1,
Type_Spot = 0x2,
Type_Hemi = 0x3,
Type_Area = 0x4
//,Type_YFPhoton = 0x5
};
ID id FAIL;
//AnimData *adt;
ID id FAIL;
//AnimData *adt;
Type type FAIL;
short flags;
Type type FAIL;
short flags;
//int mode;
//int mode;
short colormodel, totex;
float r,g,b,k WARN;
//float shdwr, shdwg, shdwb;
short colormodel, totex;
float r, g, b, k WARN;
//float shdwr, shdwg, shdwb;
float energy, dist, spotsize, spotblend;
//float haint;
float energy, dist, spotsize, spotblend;
//float haint;
float constant_coefficient;
float linear_coefficient;
float quadratic_coefficient;
float constant_coefficient;
float linear_coefficient;
float quadratic_coefficient;
float att1, att2;
//struct CurveMapping *curfalloff;
FalloffType falloff_type;
float att1, att2;
//struct CurveMapping *curfalloff;
FalloffType falloff_type;
//float clipsta, clipend, shadspotsize;
//float bias, soft, compressthresh;
//short bufsize, samp, buffers, filtertype;
//char bufflag, buftype;
//float clipsta, clipend, shadspotsize;
//float bias, soft, compressthresh;
//short bufsize, samp, buffers, filtertype;
//char bufflag, buftype;
//short ray_samp, ray_sampy, ray_sampz;
//short ray_samp_type;
short area_shape;
float area_size, area_sizey, area_sizez;
//float adapt_thresh;
//short ray_samp_method;
//short ray_samp, ray_sampy, ray_sampz;
//short ray_samp_type;
short area_shape;
float area_size, area_sizey, area_sizez;
//float adapt_thresh;
//short ray_samp_method;
//short texact, shadhalostep;
//short texact, shadhalostep;
//short sun_effect_type;
//short skyblendtype;
//float horizon_brightness;
//float spread;
float sun_brightness;
//float sun_size;
//float backscattered_light;
//float sun_intensity;
//float atm_turbidity;
//float atm_inscattering_factor;
//float atm_extinction_factor;
//float atm_distance_factor;
//float skyblendfac;
//float sky_exposure;
//short sky_colorspace;
//short sun_effect_type;
//short skyblendtype;
//float horizon_brightness;
//float spread;
float sun_brightness;
//float sun_size;
//float backscattered_light;
//float sun_intensity;
//float atm_turbidity;
//float atm_inscattering_factor;
//float atm_extinction_factor;
//float atm_distance_factor;
//float skyblendfac;
//float sky_exposure;
//short sky_colorspace;
// int YF_numphotons, YF_numsearch;
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
// float YF_causticblur, YF_ltradius;
// int YF_numphotons, YF_numsearch;
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
// float YF_causticblur, YF_ltradius;
// float YF_glowint, YF_glowofs;
// short YF_glowtype, YF_pad2;
// float YF_glowint, YF_glowofs;
// short YF_glowtype, YF_pad2;
//struct Ipo *ipo;
//struct MTex *mtex[18];
// short pr_texture;
//struct Ipo *ipo;
//struct MTex *mtex[18];
// short pr_texture;
//struct PreviewImage *preview;
//struct PreviewImage *preview;
};
// -------------------------------------------------------------------------------
struct ModifierData : ElemBase {
struct ModifierData : ElemBase {
enum ModifierType {
eModifierType_None = 0,
eModifierType_Subsurf,
eModifierType_Lattice,
eModifierType_Curve,
eModifierType_Build,
eModifierType_Mirror,
eModifierType_Decimate,
eModifierType_Wave,
eModifierType_Armature,
eModifierType_Hook,
eModifierType_Softbody,
eModifierType_Boolean,
eModifierType_Array,
eModifierType_EdgeSplit,
eModifierType_Displace,
eModifierType_UVProject,
eModifierType_Smooth,
eModifierType_Cast,
eModifierType_MeshDeform,
eModifierType_ParticleSystem,
eModifierType_ParticleInstance,
eModifierType_Explode,
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Bevel,
eModifierType_Shrinkwrap,
eModifierType_Fluidsim,
eModifierType_Mask,
eModifierType_SimpleDeform,
eModifierType_Multires,
eModifierType_Surface,
eModifierType_Smoke,
eModifierType_ShapeKey
eModifierType_None = 0,
eModifierType_Subsurf,
eModifierType_Lattice,
eModifierType_Curve,
eModifierType_Build,
eModifierType_Mirror,
eModifierType_Decimate,
eModifierType_Wave,
eModifierType_Armature,
eModifierType_Hook,
eModifierType_Softbody,
eModifierType_Boolean,
eModifierType_Array,
eModifierType_EdgeSplit,
eModifierType_Displace,
eModifierType_UVProject,
eModifierType_Smooth,
eModifierType_Cast,
eModifierType_MeshDeform,
eModifierType_ParticleSystem,
eModifierType_ParticleInstance,
eModifierType_Explode,
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Bevel,
eModifierType_Shrinkwrap,
eModifierType_Fluidsim,
eModifierType_Mask,
eModifierType_SimpleDeform,
eModifierType_Multires,
eModifierType_Surface,
eModifierType_Smoke,
eModifierType_ShapeKey
};
std::shared_ptr<ElemBase> next WARN;
@ -636,7 +625,7 @@ struct ModifierData : ElemBase {
};
// -------------------------------------------------------------------------------
struct SubsurfModifierData : ElemBase {
struct SubsurfModifierData : ElemBase {
enum Type {
@ -646,13 +635,13 @@ struct SubsurfModifierData : ElemBase {
enum Flags {
// some omitted
FLAGS_SubsurfUV =1<<3
FLAGS_SubsurfUV = 1 << 3
};
ModifierData modifier FAIL;
short subdivType WARN;
short levels FAIL;
short renderLevels ;
short renderLevels;
short flags;
};
@ -660,13 +649,13 @@ struct SubsurfModifierData : ElemBase {
struct MirrorModifierData : ElemBase {
enum Flags {
Flags_CLIPPING =1<<0,
Flags_MIRROR_U =1<<1,
Flags_MIRROR_V =1<<2,
Flags_AXIS_X =1<<3,
Flags_AXIS_Y =1<<4,
Flags_AXIS_Z =1<<5,
Flags_VGROUP =1<<6
Flags_CLIPPING = 1 << 0,
Flags_MIRROR_U = 1 << 1,
Flags_MIRROR_V = 1 << 2,
Flags_AXIS_X = 1 << 3,
Flags_AXIS_Y = 1 << 4,
Flags_AXIS_Z = 1 << 5,
Flags_VGROUP = 1 << 6
};
ModifierData modifier FAIL;
@ -677,22 +666,24 @@ struct MirrorModifierData : ElemBase {
};
// -------------------------------------------------------------------------------
struct Object : ElemBase {
struct Object : ElemBase {
ID id FAIL;
enum Type {
Type_EMPTY = 0
,Type_MESH = 1
,Type_CURVE = 2
,Type_SURF = 3
,Type_FONT = 4
,Type_MBALL = 5
Type_EMPTY = 0,
Type_MESH = 1,
Type_CURVE = 2,
Type_SURF = 3,
Type_FONT = 4,
Type_MBALL = 5
,Type_LAMP = 10
,Type_CAMERA = 11
,
Type_LAMP = 10,
Type_CAMERA = 11
,Type_WAVE = 21
,Type_LATTICE = 22
,
Type_WAVE = 21,
Type_LATTICE = 22
};
Type type FAIL;
@ -700,39 +691,29 @@ struct Object : ElemBase {
float parentinv[4][4] WARN;
char parsubstr[32] WARN;
Object* parent WARN;
Object *parent WARN;
std::shared_ptr<Object> track WARN;
std::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
std::shared_ptr<Object> proxy, proxy_from, proxy_group WARN;
std::shared_ptr<Group> dup_group WARN;
std::shared_ptr<ElemBase> data FAIL;
ListBase modifiers;
Object()
: ElemBase()
, type( Type_EMPTY )
, parent( nullptr )
, track()
, proxy()
, proxy_from()
, data() {
Object() :
ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
// empty
}
};
// -------------------------------------------------------------------------------
struct Base : ElemBase {
Base* prev WARN;
Base *prev WARN;
std::shared_ptr<Base> next WARN;
std::shared_ptr<Object> object WARN;
Base()
: ElemBase()
, prev( nullptr )
, next()
, object() {
Base() :
ElemBase(), prev(nullptr), next(), object() {
// empty
// empty
}
@ -748,11 +729,8 @@ struct Scene : ElemBase {
ListBase base;
Scene()
: ElemBase()
, camera()
, world()
, basact() {
Scene() :
ElemBase(), camera(), world(), basact() {
// empty
}
};
@ -783,9 +761,9 @@ struct Image : ElemBase {
short animspeed;
short gen_x, gen_y, gen_type;
Image()
: ElemBase() {
Image() :
ElemBase() {
// empty
}
};
@ -795,33 +773,33 @@ struct Tex : ElemBase {
// actually, the only texture type we support is Type_IMAGE
enum Type {
Type_CLOUDS = 1
,Type_WOOD = 2
,Type_MARBLE = 3
,Type_MAGIC = 4
,Type_BLEND = 5
,Type_STUCCI = 6
,Type_NOISE = 7
,Type_IMAGE = 8
,Type_PLUGIN = 9
,Type_ENVMAP = 10
,Type_MUSGRAVE = 11
,Type_VORONOI = 12
,Type_DISTNOISE = 13
,Type_POINTDENSITY = 14
,Type_VOXELDATA = 15
Type_CLOUDS = 1,
Type_WOOD = 2,
Type_MARBLE = 3,
Type_MAGIC = 4,
Type_BLEND = 5,
Type_STUCCI = 6,
Type_NOISE = 7,
Type_IMAGE = 8,
Type_PLUGIN = 9,
Type_ENVMAP = 10,
Type_MUSGRAVE = 11,
Type_VORONOI = 12,
Type_DISTNOISE = 13,
Type_POINTDENSITY = 14,
Type_VOXELDATA = 15
};
enum ImageFlags {
ImageFlags_INTERPOL = 1
,ImageFlags_USEALPHA = 2
,ImageFlags_MIPMAP = 4
,ImageFlags_IMAROT = 16
,ImageFlags_CALCALPHA = 32
,ImageFlags_NORMALMAP = 2048
,ImageFlags_GAUSS_MIP = 4096
,ImageFlags_FILTER_MIN = 8192
,ImageFlags_DERIVATIVEMAP = 16384
ImageFlags_INTERPOL = 1,
ImageFlags_USEALPHA = 2,
ImageFlags_MIPMAP = 4,
ImageFlags_IMAROT = 16,
ImageFlags_CALCALPHA = 32,
ImageFlags_NORMALMAP = 2048,
ImageFlags_GAUSS_MIP = 4096,
ImageFlags_FILTER_MIN = 8192,
ImageFlags_DERIVATIVEMAP = 16384
};
ID id FAIL;
@ -876,11 +854,8 @@ struct Tex : ElemBase {
//char use_nodes;
Tex()
: ElemBase()
, imaflag( ImageFlags_INTERPOL )
, type( Type_CLOUDS )
, ima() {
Tex() :
ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
// empty
}
};
@ -889,52 +864,52 @@ struct Tex : ElemBase {
struct MTex : ElemBase {
enum Projection {
Proj_N = 0
,Proj_X = 1
,Proj_Y = 2
,Proj_Z = 3
Proj_N = 0,
Proj_X = 1,
Proj_Y = 2,
Proj_Z = 3
};
enum Flag {
Flag_RGBTOINT = 0x1
,Flag_STENCIL = 0x2
,Flag_NEGATIVE = 0x4
,Flag_ALPHAMIX = 0x8
,Flag_VIEWSPACE = 0x10
Flag_RGBTOINT = 0x1,
Flag_STENCIL = 0x2,
Flag_NEGATIVE = 0x4,
Flag_ALPHAMIX = 0x8,
Flag_VIEWSPACE = 0x10
};
enum BlendType {
BlendType_BLEND = 0
,BlendType_MUL = 1
,BlendType_ADD = 2
,BlendType_SUB = 3
,BlendType_DIV = 4
,BlendType_DARK = 5
,BlendType_DIFF = 6
,BlendType_LIGHT = 7
,BlendType_SCREEN = 8
,BlendType_OVERLAY = 9
,BlendType_BLEND_HUE = 10
,BlendType_BLEND_SAT = 11
,BlendType_BLEND_VAL = 12
,BlendType_BLEND_COLOR = 13
BlendType_BLEND = 0,
BlendType_MUL = 1,
BlendType_ADD = 2,
BlendType_SUB = 3,
BlendType_DIV = 4,
BlendType_DARK = 5,
BlendType_DIFF = 6,
BlendType_LIGHT = 7,
BlendType_SCREEN = 8,
BlendType_OVERLAY = 9,
BlendType_BLEND_HUE = 10,
BlendType_BLEND_SAT = 11,
BlendType_BLEND_VAL = 12,
BlendType_BLEND_COLOR = 13
};
enum MapType {
MapType_COL = 1
,MapType_NORM = 2
,MapType_COLSPEC = 4
,MapType_COLMIR = 8
,MapType_REF = 16
,MapType_SPEC = 32
,MapType_EMIT = 64
,MapType_ALPHA = 128
,MapType_HAR = 256
,MapType_RAYMIRR = 512
,MapType_TRANSLU = 1024
,MapType_AMB = 2048
,MapType_DISPLACE = 4096
,MapType_WARP = 8192
MapType_COL = 1,
MapType_NORM = 2,
MapType_COLSPEC = 4,
MapType_COLMIR = 8,
MapType_REF = 16,
MapType_SPEC = 32,
MapType_EMIT = 64,
MapType_ALPHA = 128,
MapType_HAR = 256,
MapType_RAYMIRR = 512,
MapType_TRANSLU = 1024,
MapType_AMB = 2048,
MapType_DISPLACE = 4096,
MapType_WARP = 8192
};
// short texco, maptoneg;
@ -945,7 +920,7 @@ struct MTex : ElemBase {
std::shared_ptr<Tex> tex;
char uvname[32];
Projection projx,projy,projz;
Projection projx, projy, projz;
char mapping;
float ofs[3], size[3], rot;
@ -953,7 +928,7 @@ struct MTex : ElemBase {
short colormodel, pmapto, pmaptoneg;
//short normapspace, which_output;
//char brush_map_mode;
float r,g,b,k WARN;
float r, g, b, k WARN;
//float def_var, rt;
//float colfac, varfac;
@ -972,12 +947,12 @@ struct MTex : ElemBase {
//float shadowfac;
//float zenupfac, zendownfac, blendfac;
MTex()
: ElemBase() {
MTex() :
ElemBase() {
// empty
}
};
}
}
} // namespace Blender
} // namespace Assimp
#endif

File diff suppressed because it is too large Load Diff

View File

@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
*ot++ = *buffer++;
*ot = '\0';
nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
}
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,257 @@
/*
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 ColladaExporter.h
* Declares the exporter class to write a scene to a Collada file
*/
#ifndef AI_COLLADAEXPORTER_H_INC
#define AI_COLLADAEXPORTER_H_INC
#include <assimp/ai_assert.h>
#include <assimp/material.h>
#include <array>
#include <map>
#include <sstream>
#include <unordered_set>
#include <vector>
struct aiScene;
struct aiNode;
struct aiLight;
struct aiBone;
namespace Assimp {
class IOSystem;
/// Helper class to export a given scene to a Collada file. Just for my personal
/// comfort when implementing it.
class ColladaExporter {
public:
/// Constructor for a specific scene to export
ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file);
/// Destructor
virtual ~ColladaExporter();
protected:
/// Starts writing the contents
void WriteFile();
/// Writes the asset header
void WriteHeader();
/// Writes the embedded textures
void WriteTextures();
/// Writes the material setup
void WriteMaterials();
/// Writes the cameras library
void WriteCamerasLibrary();
// Write a camera entry
void WriteCamera(size_t pIndex);
/// Writes the cameras library
void WriteLightsLibrary();
// Write a camera entry
void WriteLight(size_t pIndex);
void WritePointLight(const aiLight *const light);
void WriteDirectionalLight(const aiLight *const light);
void WriteSpotLight(const aiLight *const light);
void WriteAmbienttLight(const aiLight *const light);
/// Writes the controller library
void WriteControllerLibrary();
/// Writes a skin controller of the given mesh
void WriteController(size_t pIndex);
/// Writes the geometry library
void WriteGeometryLibrary();
/// Writes the given mesh
void WriteGeometry(size_t pIndex);
//enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
// customized to add animation related type
enum FloatDataType { FloatType_Vector,
FloatType_TexCoord2,
FloatType_TexCoord3,
FloatType_Color,
FloatType_Mat4x4,
FloatType_Weight,
FloatType_Time };
/// Writes a float array of the given type
void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount);
/// Writes the scene library
void WriteSceneLibrary();
// customized, Writes the animation library
void WriteAnimationsLibrary();
void WriteAnimationLibrary(size_t pIndex);
std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call.
/// Recursively writes the given node
void WriteNode(const aiNode *pNode);
/// Enters a new xml element, which increases the indentation
void PushTag() { startstr.append(" "); }
/// Leaves an element, decreasing the indentation
void PopTag() {
ai_assert(startstr.length() > 1);
startstr.erase(startstr.length() - 2);
}
void CreateNodeIds(const aiNode *node);
/// Get or Create a unique Node ID string for the given Node
std::string GetNodeUniqueId(const aiNode *node);
std::string GetNodeName(const aiNode *node);
std::string GetBoneUniqueId(const aiBone *bone);
enum class AiObjectType {
Mesh,
Material,
Animation,
Light,
Camera,
Count,
};
/// Get or Create a unique ID string for the given scene object index
std::string GetObjectUniqueId(AiObjectType type, size_t pIndex);
/// Get or Create a name string for the given scene object index
std::string GetObjectName(AiObjectType type, size_t pIndex);
typedef std::map<size_t, std::string> IndexIdMap;
typedef std::pair<std::string, std::string> NameIdPair;
NameIdPair AddObjectIndexToMaps(AiObjectType type, size_t pIndex);
// Helpers
inline IndexIdMap &GetObjectIdMap(AiObjectType type) { return mObjectIdMap[static_cast<size_t>(type)]; }
inline IndexIdMap &GetObjectNameMap(AiObjectType type) { return mObjectNameMap[static_cast<size_t>(type)]; }
private:
std::unordered_set<std::string> mUniqueIds; // Cache of used unique ids
std::map<const void *, std::string> mNodeIdMap; // Cache of encoded node and bone ids
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectIdMap; // Cache of encoded unique IDs
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectNameMap; // Cache of encoded names
public:
/// Stringstream to write all output into
std::stringstream mOutput;
/// The IOSystem for output
IOSystem *mIOSystem;
/// Path of the directory where the scene will be exported
const std::string mPath;
/// Name of the file (without extension) where the scene will be exported
const std::string mFile;
/// The scene to be written
const aiScene *const mScene;
std::string mSceneId;
bool mAdd_root_node = false;
/// current line start string, contains the current indentation for simple stream insertion
std::string startstr;
/// current line end string for simple stream insertion
const std::string endstr;
// pair of color and texture - texture precedences color
struct Surface {
bool exist;
aiColor4D color;
std::string texture;
size_t channel;
Surface() {
exist = false;
channel = 0;
}
};
struct Property {
bool exist;
ai_real value;
Property() :
exist(false),
value(0.0) {}
};
// summarize a material in an convenient way.
struct Material {
std::string id;
std::string name;
std::string shading_model;
Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
Property shininess, transparency, index_refraction;
Material() {}
};
std::map<unsigned int, std::string> textures;
public:
/// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
/// Reads a single surface entry from the given material keys
bool ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex);
/// Writes an image entry for the given surface
void WriteImageEntry(const Surface &pSurface, const std::string &imageId);
/// Writes the two parameters necessary for referencing a texture in an effect entry
void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId);
/// Writes a color-or-texture entry into an effect definition
void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId);
/// Writes a scalar property
void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName);
};
} // namespace Assimp
#endif // !! AI_COLLADAEXPORTER_H_INC

View File

@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaHelper.h"
#include <assimp/commonMetaData.h>
#include <assimp/ParsingUtils.h>
#include <assimp/commonMetaData.h>
namespace Assimp {
namespace Collada {
@ -63,42 +63,35 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
for (auto &val : result)
{
for (auto &val : result) {
ToCamelCase(val.first);
}
return result;
};
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
{
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
return result;
}
// ------------------------------------------------------------------------------------------------
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
void ToCamelCase(std::string &text)
{
void ToCamelCase(std::string &text) {
if (text.empty())
return;
// Capitalise first character
auto it = text.begin();
(*it) = ToUpper(*it);
++it;
for (/*started above*/ ; it != text.end(); /*iterated below*/)
{
if ((*it) == '_')
{
for (/*started above*/; it != text.end(); /*iterated below*/) {
if ((*it) == '_') {
it = text.erase(it);
if (it != text.end())
(*it) = ToUpper(*it);
}
else
{
} else {
// Make lower case
(*it) = ToLower(*it);
++it;
++it;
}
}
}

View File

@ -45,31 +45,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_COLLADAHELPER_H_INC
#define AI_COLLADAHELPER_H_INC
#include <map>
#include <vector>
#include <set>
#include <stdint.h>
#include <assimp/light.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <stdint.h>
#include <map>
#include <set>
#include <vector>
struct aiMaterial;
namespace Assimp {
namespace Collada {
namespace Assimp {
namespace Collada {
/** Collada file versions which evolved during the years ... */
enum FormatVersion
{
enum FormatVersion {
FV_1_5_n,
FV_1_4_n,
FV_1_3_n
};
/** Transformation types that can be applied to a node */
enum TransformType
{
enum TransformType {
TF_LOOKAT,
TF_ROTATE,
TF_TRANSLATE,
@ -79,10 +76,9 @@ enum TransformType
};
/** Different types of input data to a vertex or face */
enum InputType
{
enum InputType {
IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Position,
IT_Normal,
IT_Texcoord,
@ -92,15 +88,13 @@ enum InputType
};
/** Supported controller types */
enum ControllerType
{
enum ControllerType {
Skin,
Morph
};
/** Supported morph methods */
enum MorphMethod
{
enum MorphMethod {
Normalized,
Relative
};
@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
void ToCamelCase(std::string &text);
/** Contains all data for one of the different transformation types */
struct Transform
{
std::string mID; ///< SID of the transform step, by which anim channels address their target node
struct Transform {
std::string mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType;
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
};
/** A collada camera. */
struct Camera
{
Camera()
: mOrtho (false)
, mHorFov (10e10f)
, mVerFov (10e10f)
, mAspect (10e10f)
, mZNear (0.1f)
, mZFar (1000.f)
{}
struct Camera {
Camera() :
mOrtho(false),
mHorFov(10e10f),
mVerFov(10e10f),
mAspect(10e10f),
mZNear(0.1f),
mZFar(1000.f) {}
// Name of camera
std::string mName;
@ -159,19 +150,17 @@ struct Camera
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
/** A collada light source. */
struct Light
{
Light()
: mType (aiLightSource_UNDEFINED)
, mAttConstant (1.f)
, mAttLinear (0.f)
, mAttQuadratic (0.f)
, mFalloffAngle (180.f)
, mFalloffExponent (0.f)
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
, mIntensity (1.f)
{}
struct Light {
Light() :
mType(aiLightSource_UNDEFINED),
mAttConstant(1.f),
mAttLinear(0.f),
mAttQuadratic(0.f),
mFalloffAngle(180.f),
mFalloffExponent(0.f),
mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
mIntensity(1.f) {}
//! Type of the light source aiLightSourceType + ambient
unsigned int mType;
@ -180,7 +169,7 @@ struct Light
aiColor3D mColor;
//! Light attenuation
ai_real mAttConstant,mAttLinear,mAttQuadratic;
ai_real mAttConstant, mAttLinear, mAttQuadratic;
//! Spot light falloff
ai_real mFalloffAngle;
@ -198,12 +187,10 @@ struct Light
};
/** Short vertex index description */
struct InputSemanticMapEntry
{
InputSemanticMapEntry()
: mSet(0)
, mType(IT_Invalid)
{}
struct InputSemanticMapEntry {
InputSemanticMapEntry() :
mSet(0),
mType(IT_Invalid) {}
//! Index of set, optional
unsigned int mSet;
@ -213,8 +200,7 @@ struct InputSemanticMapEntry
};
/** Table to map from effect to vertex input semantics */
struct SemanticMappingTable
{
struct SemanticMappingTable {
//! Name of material
std::string mMatName;
@ -222,7 +208,7 @@ struct SemanticMappingTable
std::map<std::string, InputSemanticMapEntry> mMap;
//! For std::find
bool operator == (const std::string& s) const {
bool operator==(const std::string &s) const {
return s == mMatName;
}
};
@ -230,8 +216,7 @@ struct SemanticMappingTable
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
* The ID refers to either a mesh or a controller which specifies the mesh
*/
struct MeshInstance
{
struct MeshInstance {
///< ID of the mesh or controller to be instanced
std::string mMeshOrController;
@ -240,34 +225,30 @@ struct MeshInstance
};
/** A reference to a camera inside a node*/
struct CameraInstance
{
///< ID of the camera
struct CameraInstance {
///< ID of the camera
std::string mCamera;
};
/** A reference to a light inside a node*/
struct LightInstance
{
///< ID of the camera
struct LightInstance {
///< ID of the camera
std::string mLight;
};
/** A reference to a node inside a node*/
struct NodeInstance
{
///< ID of the node
struct NodeInstance {
///< ID of the node
std::string mNode;
};
/** A node in a scene hierarchy */
struct Node
{
struct Node {
std::string mName;
std::string mID;
std::string mSID;
Node* mParent;
std::vector<Node*> mChildren;
Node *mParent;
std::vector<Node *> mChildren;
/** Operations in order to calculate the resulting transformation to parent. */
std::vector<Transform> mTransforms;
@ -288,80 +269,83 @@ struct Node
std::string mPrimaryCamera;
//! Constructor. Begin with a zero parent
Node()
: mParent( nullptr ){
Node() :
mParent(nullptr) {
// empty
}
//! Destructor: delete all children subsequently
~Node() {
for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
delete *it;
}
};
/** Data source array: either floats or strings */
struct Data
{
struct Data {
bool mIsStringArray;
std::vector<ai_real> mValues;
std::vector<std::string> mStrings;
};
/** Accessor to a data array */
struct Accessor
{
size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values
size_t mStride; // Stride in number of values
struct Accessor {
size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values
size_t mStride; // Stride in number of values
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
std::string mSource; // URL of the source array
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
std::string mSource; // URL of the source array
mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
Accessor()
{
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
Accessor() {
mCount = 0;
mSize = 0;
mOffset = 0;
mStride = 0;
mData = nullptr;
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
}
};
/** A single face in a mesh */
struct Face
{
struct Face {
std::vector<size_t> mIndices;
};
/** An input channel for mesh data, referring to a single accessor */
struct InputChannel
{
InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
struct InputChannel {
InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
std::string mAccessor; // ID of the accessor where to read the actual values from.
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. nullptr else
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
InputChannel() {
mType = IT_Invalid;
mIndex = 0;
mOffset = 0;
mResolved = nullptr;
}
};
/** Subset of a mesh with a certain material */
struct SubMesh
{
struct SubMesh {
std::string mMaterial; ///< subgroup identifier
size_t mNumFaces; ///< number of faces in this submesh
};
/** Contains data for a single mesh */
struct Mesh
{
Mesh()
{
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
struct Mesh {
Mesh(const std::string &id) :
mId(id) {
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
mNumUVComponents[i] = 2;
}
const std::string mId;
std::string mName;
// just to check if there's some sophisticated addressing involved...
@ -377,7 +361,7 @@ struct Mesh
std::vector<aiVector3D> mTangents;
std::vector<aiVector3D> mBitangents;
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
@ -394,8 +378,7 @@ struct Mesh
};
/** Which type of primitives the ReadPrimitives() function is going to read */
enum PrimitiveType
{
enum PrimitiveType {
Prim_Invalid,
Prim_Lines,
Prim_LineStrip,
@ -407,8 +390,7 @@ enum PrimitiveType
};
/** A skeleton controller to deform a mesh with the use of joints */
struct Controller
{
struct Controller {
// controller type
ControllerType mType;
@ -436,36 +418,32 @@ struct Controller
std::vector<size_t> mWeightCounts;
// JointIndex-WeightIndex pairs for all vertices
std::vector< std::pair<size_t, size_t> > mWeights;
std::vector<std::pair<size_t, size_t>> mWeights;
std::string mMorphTarget;
std::string mMorphWeight;
};
/** A collada material. Pretty much the only member is a reference to an effect. */
struct Material
{
struct Material {
std::string mName;
std::string mEffect;
};
/** Type of the effect param */
enum ParamType
{
enum ParamType {
Param_Sampler,
Param_Surface
};
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
struct EffectParam
{
struct EffectParam {
ParamType mType;
std::string mReference; // to which other thing the param is referring to.
};
/** Shading type supported by the standard effect spec of Collada */
enum ShadeType
{
enum ShadeType {
Shade_Invalid,
Shade_Constant,
Shade_Lambert,
@ -474,18 +452,16 @@ enum ShadeType
};
/** Represents a texture sampler in collada */
struct Sampler
{
Sampler()
: mWrapU (true)
, mWrapV (true)
, mMirrorU ()
, mMirrorV ()
, mOp (aiTextureOp_Multiply)
, mUVId (UINT_MAX)
, mWeighting (1.f)
, mMixWithPrevious (1.f)
{}
struct Sampler {
Sampler() :
mWrapU(true),
mWrapV(true),
mMirrorU(),
mMirrorV(),
mOp(aiTextureOp_Multiply),
mUVId(UINT_MAX),
mWeighting(1.f),
mMixWithPrevious(1.f) {}
/** Name of image reference
*/
@ -537,18 +513,17 @@ struct Sampler
/** A collada effect. Can contain about anything according to the Collada spec,
but we limit our version to a reasonable subset. */
struct Effect
{
struct Effect {
// Shading mode
ShadeType mShadeType;
// Colors
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
mTransparent, mReflective;
mTransparent, mReflective;
// Textures
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
mTexTransparent, mTexBump, mTexReflective;
mTexTransparent, mTexBump, mTexReflective;
// Scalar factory
ai_real mShininess, mRefractIndex, mReflectivity;
@ -566,30 +541,28 @@ struct Effect
// Double-sided?
bool mDoubleSided, mWireframe, mFaceted;
Effect()
: mShadeType (Shade_Phong)
, mEmissive ( 0, 0, 0, 1)
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
, mTransparent ( 0, 0, 0, 1)
, mShininess (10.0f)
, mRefractIndex (1.f)
, mReflectivity (0.f)
, mTransparency (1.f)
, mHasTransparency (false)
, mRGBTransparency(false)
, mInvertTransparency(false)
, mDoubleSided (false)
, mWireframe (false)
, mFaceted (false)
{
Effect() :
mShadeType(Shade_Phong),
mEmissive(0, 0, 0, 1),
mAmbient(0.1f, 0.1f, 0.1f, 1),
mDiffuse(0.6f, 0.6f, 0.6f, 1),
mSpecular(0.4f, 0.4f, 0.4f, 1),
mTransparent(0, 0, 0, 1),
mShininess(10.0f),
mRefractIndex(1.f),
mReflectivity(0.f),
mTransparency(1.f),
mHasTransparency(false),
mRGBTransparency(false),
mInvertTransparency(false),
mDoubleSided(false),
mWireframe(false),
mFaceted(false) {
}
};
/** An image, meaning texture */
struct Image
{
struct Image {
std::string mFileName;
/** Embedded image data */
@ -600,8 +573,7 @@ struct Image
};
/** An animation channel. */
struct AnimationChannel
{
struct AnimationChannel {
/** URL of the data to animate. Could be about anything, but we support only the
* "NodeID/TransformID.SubElement" notation
*/
@ -620,8 +592,7 @@ struct AnimationChannel
};
/** An animation. Container for 0-x animation channels or 0-x animations */
struct Animation
{
struct Animation {
/** Anim name */
std::string mName;
@ -629,96 +600,86 @@ struct Animation
std::vector<AnimationChannel> mChannels;
/** the sub-animations, if any */
std::vector<Animation*> mSubAnims;
std::vector<Animation *> mSubAnims;
/** Destructor */
~Animation()
{
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
~Animation() {
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
delete *it;
}
/** Collect all channels in the animation hierarchy into a single channel list. */
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
{
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
/** Collect all channels in the animation hierarchy into a single channel list. */
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
{
Animation *pAnim = (*it);
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
Animation *pAnim = (*it);
pAnim->CollectChannelsRecursively(channels);
}
}
pAnim->CollectChannelsRecursively(channels);
}
}
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
void CombineSingleChannelAnimations()
{
CombineSingleChannelAnimationsRecursively(this);
}
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
void CombineSingleChannelAnimations() {
CombineSingleChannelAnimationsRecursively(this);
}
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
{
std::set<std::string> childrenTargets;
bool childrenAnimationsHaveDifferentChannels = true;
void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
std::set<std::string> childrenTargets;
bool childrenAnimationsHaveDifferentChannels = true;
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
{
Animation *anim = *it;
CombineSingleChannelAnimationsRecursively(anim);
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
Animation *anim = *it;
CombineSingleChannelAnimationsRecursively(anim);
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
childrenTargets.insert(anim->mChannels[0].mTarget);
} else {
childrenAnimationsHaveDifferentChannels = false;
}
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
childrenTargets.insert(anim->mChannels[0].mTarget);
} else {
childrenAnimationsHaveDifferentChannels = false;
}
++it;
}
++it;
}
// We only want to combine animations if they have different channels
if (childrenAnimationsHaveDifferentChannels)
{
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
{
Animation *anim = *it;
// We only want to combine animations if they have different channels
if (childrenAnimationsHaveDifferentChannels) {
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
Animation *anim = *it;
pParent->mChannels.push_back(anim->mChannels[0]);
pParent->mChannels.push_back(anim->mChannels[0]);
it = pParent->mSubAnims.erase(it);
it = pParent->mSubAnims.erase(it);
delete anim;
continue;
}
}
}
delete anim;
continue;
}
}
}
};
/** Description of a collada animation channel which has been determined to affect the current node */
struct ChannelEntry
{
const Collada::AnimationChannel* mChannel; ///> the source channel
struct ChannelEntry {
const Collada::AnimationChannel *mChannel; ///> the source channel
std::string mTargetId;
std::string mTransformId; // the ID of the transformation step of the node which is influenced
std::string mTransformId; // the ID of the transformation step of the node which is influenced
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
size_t mSubElement; // starting index inside the transform data
// resolved data references
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data* mTimeData; ///> Source data array for the time values
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data* mValueData; ///> Source datat array for the key value values
const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data *mTimeData; ///> Source data array for the time values
const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data *mValueData; ///> Source datat array for the key value values
ChannelEntry()
: mChannel()
, mTransformIndex()
, mSubElement()
, mTimeAccessor()
, mTimeData()
, mValueAccessor()
, mValueData()
{}
ChannelEntry() :
mChannel(),
mTransformIndex(),
mSubElement(),
mTimeAccessor(),
mTimeData(),
mValueAccessor(),
mValueData() {}
};
} // end of namespace Collada

View File

@ -0,0 +1,392 @@
/*
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 ColladaParser.h
* @brief Defines the parser helper class for the collada loader
*/
#ifndef AI_COLLADAPARSER_H_INC
#define AI_COLLADAPARSER_H_INC
#include "ColladaHelper.h"
#include <assimp/TinyFormatter.h>
#include <assimp/ai_assert.h>
#include <assimp/irrXMLWrapper.h>
namespace Assimp {
class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader.
*
* Does all the XML reading and builds internal data structures from it,
* but leaves the resolving of all the references to the loader.
*/
class ColladaParser {
friend class ColladaLoader;
/** Converts a path read from a collada file to the usual representation */
static void UriDecodePath(aiString &ss);
protected:
/** Map for generic metadata as aiString */
typedef std::map<std::string, aiString> StringMetaData;
/** Constructor from XML file */
ColladaParser(IOSystem *pIOHandler, const std::string &pFile);
/** Destructor */
~ColladaParser();
/** Attempts to read the ZAE manifest and returns the DAE to open */
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
/** Reads the contents of the file */
void ReadContents();
/** Reads the structure of the file */
void ReadStructure();
/** Reads asset information such as coordinate system information and legal blah */
void ReadAssetInfo();
/** Reads contributor information such as author and legal blah */
void ReadContributorInfo();
/** Reads generic metadata into provided map and renames keys for Assimp */
void ReadMetaDataItem(StringMetaData &metadata);
/** Reads the animation library */
void ReadAnimationLibrary();
/** Reads the animation clip library */
void ReadAnimationClipLibrary();
/** Unwrap controllers dependency hierarchy */
void PostProcessControllers();
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
void PostProcessRootAnimations();
/** Reads an animation into the given parent structure */
void ReadAnimation(Collada::Animation *pParent);
/** Reads an animation sampler into the given anim channel */
void ReadAnimationSampler(Collada::AnimationChannel &pChannel);
/** Reads the skeleton controller library */
void ReadControllerLibrary();
/** Reads a controller into the given mesh structure */
void ReadController(Collada::Controller &pController);
/** Reads the joint definitions for the given controller */
void ReadControllerJoints(Collada::Controller &pController);
/** Reads the joint weights for the given controller */
void ReadControllerWeights(Collada::Controller &pController);
/** Reads the image library contents */
void ReadImageLibrary();
/** Reads an image entry into the given image */
void ReadImage(Collada::Image &pImage);
/** Reads the material library */
void ReadMaterialLibrary();
/** Reads a material entry into the given material */
void ReadMaterial(Collada::Material &pMaterial);
/** Reads the camera library */
void ReadCameraLibrary();
/** Reads a camera entry into the given camera */
void ReadCamera(Collada::Camera &pCamera);
/** Reads the light library */
void ReadLightLibrary();
/** Reads a light entry into the given light */
void ReadLight(Collada::Light &pLight);
/** Reads the effect library */
void ReadEffectLibrary();
/** Reads an effect entry into the given effect*/
void ReadEffect(Collada::Effect &pEffect);
/** Reads an COMMON effect profile */
void ReadEffectProfileCommon(Collada::Effect &pEffect);
/** Read sampler properties */
void ReadSamplerProperties(Collada::Sampler &pSampler);
/** Reads an effect entry containing a color or a texture defining that color */
void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler);
/** Reads an effect entry containing a float */
void ReadEffectFloat(ai_real &pFloat);
/** Reads an effect parameter specification of any kind */
void ReadEffectParam(Collada::EffectParam &pParam);
/** Reads the geometry library contents */
void ReadGeometryLibrary();
/** Reads a geometry from the geometry library. */
void ReadGeometry(Collada::Mesh &pMesh);
/** Reads a mesh from the geometry library */
void ReadMesh(Collada::Mesh &pMesh);
/** Reads a source element - a combination of raw data and an accessor defining
* things that should not be redefinable. Yes, that's another rant.
*/
void ReadSource();
/** Reads a data array holding a number of elements, and stores it in the global library.
* Currently supported are array of floats and arrays of strings.
*/
void ReadDataArray();
/** Reads an accessor and stores it in the global library under the given ID -
* accessors use the ID of the parent <source> element
*/
void ReadAccessor(const std::string &pID);
/** Reads input declarations of per-vertex mesh data into the given mesh */
void ReadVertexData(Collada::Mesh &pMesh);
/** Reads input declarations of per-index mesh data into the given mesh */
void ReadIndexData(Collada::Mesh &pMesh);
/** Reads a single input channel element and stores it in the given array, if valid */
void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t currentPrimitive, const std::vector<size_t> &indices);
/** Reads one triangle of a tristrip into the mesh */
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh,
std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices);
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
/** Reads the library of node hierarchies and scene parts */
void ReadSceneLibrary();
/** Reads a scene node's contents including children and stores it in the given node */
void ReadSceneNode(Collada::Node *pNode);
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
void ReadNodeTransformation(Collada::Node *pNode, Collada::TransformType pType);
/** Reads a mesh reference in a node and adds it to the node's mesh list */
void ReadNodeGeometry(Collada::Node *pNode);
/** Reads the collada scene */
void ReadScene();
// Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl);
/** Reads embedded textures from a ZAE archive*/
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected:
/** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX;
void ReportWarning(const char *msg, ...);
/** Skips all data until the end node of the current element */
void SkipElement();
/** Skips all data until the end node of the given element */
void SkipElement(const char *pElement);
/** Compares the current xml element name to the given string and returns true if equal */
bool IsElement(const char *pName) const;
/** Tests for the opening tag of the given element, throws an exception if not found */
void TestOpening(const char *pName);
/** Tests for the closing tag of the given element, throws an exception if not found */
void TestClosing(const char *pName);
/** Checks the present element for the presence of the attribute, returns its index
or throws an exception if not found */
int GetAttribute(const char *pAttr) const;
/** Returns the index of the named attribute or -1 if not found. Does not throw,
therefore useful for optional attributes */
int TestAttribute(const char *pAttr) const;
/** Reads the text contents of an element, throws an exception if not given.
Skips leading whitespace. */
const char *GetTextContent();
/** Reads the text contents of an element, returns nullptr if not given.
Skips leading whitespace. */
const char *TestTextContent();
/** Reads a single bool from current text content */
bool ReadBoolFromTextContent();
/** Reads a single float from current text content */
ai_real ReadFloatFromTextContent();
/** Calculates the resulting transformation from all the given transform steps */
aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
/** Determines the input data type for the given semantic string */
Collada::InputType GetTypeForSemantic(const std::string &pSemantic);
/** Finds the item in the given library by its reference, throws if not found */
template <typename Type>
const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
protected:
/** Filename, for a verbose error message */
std::string mFileName;
/** XML reader, member for everyday use */
irr::io::IrrXMLReader *mReader;
/** All data arrays found in the file by ID. Might be referred to by actually
everyone. Collada, you are a steaming pile of indirection. */
typedef std::map<std::string, Collada::Data> DataLibrary;
DataLibrary mDataLibrary;
/** Same for accessors which define how the data in a data array is accessed. */
typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
AccessorLibrary mAccessorLibrary;
/** Mesh library: mesh by ID */
typedef std::map<std::string, Collada::Mesh *> MeshLibrary;
MeshLibrary mMeshLibrary;
/** node library: root node of the hierarchy part by ID */
typedef std::map<std::string, Collada::Node *> NodeLibrary;
NodeLibrary mNodeLibrary;
/** Image library: stores texture properties by ID */
typedef std::map<std::string, Collada::Image> ImageLibrary;
ImageLibrary mImageLibrary;
/** Effect library: surface attributes by ID */
typedef std::map<std::string, Collada::Effect> EffectLibrary;
EffectLibrary mEffectLibrary;
/** Material library: surface material by ID */
typedef std::map<std::string, Collada::Material> MaterialLibrary;
MaterialLibrary mMaterialLibrary;
/** Light library: surface light by ID */
typedef std::map<std::string, Collada::Light> LightLibrary;
LightLibrary mLightLibrary;
/** Camera library: surface material by ID */
typedef std::map<std::string, Collada::Camera> CameraLibrary;
CameraLibrary mCameraLibrary;
/** Controller library: joint controllers by ID */
typedef std::map<std::string, Collada::Controller> ControllerLibrary;
ControllerLibrary mControllerLibrary;
/** Animation library: animation references by ID */
typedef std::map<std::string, Collada::Animation *> AnimationLibrary;
AnimationLibrary mAnimationLibrary;
/** Animation clip library: clip animation references by ID */
typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary;
AnimationClipLibrary mAnimationClipLibrary;
/** Pointer to the root node. Don't delete, it just points to one of
the nodes in the node library. */
Collada::Node *mRootNode;
/** Root animation container */
Collada::Animation mAnims;
/** Size unit: how large compared to a meter */
ai_real mUnitSize;
/** Which is the up vector */
enum { UP_X,
UP_Y,
UP_Z } mUpDirection;
/** Asset metadata (global for scene) */
StringMetaData mAssetMetaData;
/** Collada file format version */
Collada::FormatVersion mFormat;
};
// ------------------------------------------------------------------------------------------------
// Check for element match
inline bool ColladaParser::IsElement(const char *pName) const {
ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT);
return ::strcmp(mReader->getNodeName(), pName) == 0;
}
// ------------------------------------------------------------------------------------------------
// Finds the item in the given library by its reference, throws if not found
template <typename Type>
const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
if (it == pLibrary.end())
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\".");
return it->second;
}
} // end of namespace Assimp
#endif // AI_COLLADAPARSER_H_INC

View File

@ -135,7 +135,7 @@ public:
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
splitter++;
ASSIMP_LOG_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
ASSIMP_LOG_VERBOSE_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
}
} catch(std::logic_error&) {
ai_assert(!splitter);

View File

@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
#include "DXF/DXFLoader.h"
#include "DXF/DXFHelper.h"
#include "AssetLib/DXF/DXFLoader.h"
#include "AssetLib/DXF/DXFHelper.h"
#include "PostProcessing/ConvertToLHProcess.h"
#include <assimp/ParsingUtils.h>
@ -241,7 +241,7 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
}
}
ASSIMP_LOG_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
}
if (! output.blocks.size() ) {
@ -473,7 +473,7 @@ void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
++reader;
}
ASSIMP_LOG_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
}
// ------------------------------------------------------------------------------------------------
@ -549,7 +549,7 @@ void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output)
++reader;
}
ASSIMP_LOG_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
ASSIMP_LOG_VERBOSE_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
" inserted blocks in ENTITIES" );
}

View File

@ -47,10 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#include "FBXParser.h"
#include "FBXDocument.h"
#include "FBXImporter.h"
#include "FBXDocumentUtil.h"
#include "FBXImporter.h"
#include "FBXParser.h"
namespace Assimp {
namespace FBX {
@ -58,65 +58,60 @@ namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
: Object(id, element, name)
{
const Scope& sc = GetRequiredScope(element);
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::string &name, const Document & /*doc*/) :
Object(id, element, name) {
const Scope &sc = GetRequiredScope(element);
const Element &KeyTime = GetRequiredElement(sc, "KeyTime");
const Element &KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
ParseVectorDataArray(keys, KeyTime);
ParseVectorDataArray(values, KeyValueFloat);
if(keys.size() != values.size()) {
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
if (keys.size() != values.size()) {
DOMError("the number of key times does not match the number of keyframe values", &KeyTime);
}
// check if the key times are well-ordered
if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
DOMError("the keyframes are not in ascending order",&KeyTime);
if (!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
DOMError("the keyframes are not in ascending order", &KeyTime);
}
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
if(KeyAttrDataFloat) {
const Element *KeyAttrDataFloat = sc["KeyAttrDataFloat"];
if (KeyAttrDataFloat) {
ParseVectorDataArray(attributes, *KeyAttrDataFloat);
}
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
if(KeyAttrFlags) {
const Element *KeyAttrFlags = sc["KeyAttrFlags"];
if (KeyAttrFlags) {
ParseVectorDataArray(flags, *KeyAttrFlags);
}
}
// ------------------------------------------------------------------------------------------------
AnimationCurve::~AnimationCurve()
{
AnimationCurve::~AnimationCurve() {
// empty
}
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name,
const Document& doc, const char* const * target_prop_whitelist /*= NULL*/,
size_t whitelist_size /*= 0*/)
: Object(id, element, name)
, target()
, doc(doc)
{
const Scope& sc = GetRequiredScope(element);
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) :
Object(id, element, name), target(), doc(doc) {
const Scope &sc = GetRequiredScope(element);
// find target node
const char* whitelist[] = {"Model","NodeAttribute","Deformer"};
const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3);
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
for(const Connection* con : conns) {
for (const Connection *con : conns) {
// link should go for a property
if (!con->PropertyName().length()) {
continue;
}
if(target_prop_whitelist) {
const char* const s = con->PropertyName().c_str();
if (target_prop_whitelist) {
const char *const s = con->PropertyName().c_str();
bool ok = false;
for (size_t i = 0; i < whitelist_size; ++i) {
if (!strcmp(s, target_prop_whitelist[i])) {
@ -130,16 +125,14 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
}
}
const Object* const ob = con->DestinationObject();
if(!ob) {
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
const Object *const ob = con->DestinationObject();
if (!ob) {
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", &element);
continue;
}
// XXX support constraints as DOM class
//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
target = ob;
if(!target) {
if (!target) {
continue;
}
@ -147,42 +140,40 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
break;
}
if(!target) {
DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
if (!target) {
DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode", &element);
}
props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
}
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::~AnimationCurveNode()
{
AnimationCurveNode::~AnimationCurveNode() {
// empty
}
// ------------------------------------------------------------------------------------------------
const AnimationCurveMap& AnimationCurveNode::Curves() const
{
if ( curves.empty() ) {
const AnimationCurveMap &AnimationCurveNode::Curves() const {
if (curves.empty()) {
// resolve attached animation curves
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
for(const Connection* con : conns) {
for (const Connection *con : conns) {
// link should go for a property
if (!con->PropertyName().length()) {
continue;
}
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
const Object *const ob = con->SourceObject();
if (nullptr == ob) {
DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
continue;
}
const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
if(!anim) {
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
if (nullptr == anim) {
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
continue;
}
@ -194,53 +185,49 @@ const AnimationCurveMap& AnimationCurveNode::Curves() const
}
// ------------------------------------------------------------------------------------------------
AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Object(id, element, name)
, doc(doc)
{
const Scope& sc = GetRequiredScope(element);
AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Object(id, element, name), doc(doc) {
const Scope &sc = GetRequiredScope(element);
// note: the props table here bears little importance and is usually absent
props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
}
// ------------------------------------------------------------------------------------------------
AnimationLayer::~AnimationLayer()
{
AnimationLayer::~AnimationLayer() {
// empty
}
// ------------------------------------------------------------------------------------------------
AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
size_t whitelist_size /*= 0*/) const
{
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) const {
AnimationCurveNodeList nodes;
// resolve attached animation nodes
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
nodes.reserve(conns.size());
for(const Connection* con : conns) {
for (const Connection *con : conns) {
// link should not go to a property
if (con->PropertyName().length()) {
continue;
}
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
const Object *const ob = con->SourceObject();
if (!ob) {
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", &element);
continue;
}
const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
if(!anim) {
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
const AnimationCurveNode *const anim = dynamic_cast<const AnimationCurveNode *>(ob);
if (!anim) {
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", &element);
continue;
}
if(target_prop_whitelist) {
const char* s = anim->TargetProperty().c_str();
if (target_prop_whitelist) {
const char *s = anim->TargetProperty().c_str();
bool ok = false;
for (size_t i = 0; i < whitelist_size; ++i) {
if (!strcmp(s, target_prop_whitelist[i])) {
@ -248,7 +235,7 @@ AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whi
break;
}
}
if(!ok) {
if (!ok) {
continue;
}
}
@ -259,34 +246,33 @@ AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whi
}
// ------------------------------------------------------------------------------------------------
AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Object(id, element, name)
{
const Scope& sc = GetRequiredScope(element);
AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
Object(id, element, name) {
const Scope &sc = GetRequiredScope(element);
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
// resolve attached animation layers
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
layers.reserve(conns.size());
for(const Connection* con : conns) {
for (const Connection *con : conns) {
// link should not go to a property
if (con->PropertyName().length()) {
continue;
}
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
const Object *const ob = con->SourceObject();
if (!ob) {
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", &element);
continue;
}
const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
if(!anim) {
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
const AnimationLayer *const anim = dynamic_cast<const AnimationLayer *>(ob);
if (!anim) {
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", &element);
continue;
}
layers.push_back(anim);
@ -294,12 +280,11 @@ AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::s
}
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack()
{
AnimationStack::~AnimationStack() {
// empty
}
} //!FBX
} //!Assimp
} // namespace FBX
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

View File

@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdint.h>
#include <assimp/Exceptional.h>
#include <assimp/ByteSwapper.h>
#include <assimp/DefaultLogger.hpp>
namespace Assimp {
namespace FBX {
@ -426,7 +427,8 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
{
ai_assert(input);
ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
if(length < 0x1b) {
TokenizeError("file is too short",0);
@ -451,6 +453,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
/*Result ignored*/ ReadByte(input, cursor, input + length);
/*Result ignored*/ ReadByte(input, cursor, input + length);
const uint32_t version = ReadWord(input, cursor, input + length);
ASSIMP_LOG_DEBUG_F("FBX version: ", version);
const bool is64bits = version >= 7500;
const char *end = input + length;
while (cursor < end ) {

View File

@ -105,7 +105,7 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
// The idea here is to traverse all objects to find these Textures and convert them,
// so later during material conversion it will find converted texture in the textures_converted array.
if (doc.Settings().readTextures) {
ConvertOrphantEmbeddedTextures();
ConvertOrphanedEmbeddedTextures();
}
ConvertRootNode();
@ -804,11 +804,6 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
}
// is_complex needs to be consistent with NeedsComplexTransformationChain()
// or the interplay between this code and the animation converter would
// not be guaranteed.
//ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0));
// now, if we have more than just Translation, Scaling and Rotation,
// we need to generate a full node chain to accommodate for assimp's
// lack to express pivots and offsets.
@ -1163,7 +1158,8 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
//losing channel name if using shapeGeometry->Name()
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name()));
for (size_t j = 0; j < curIndices.size(); j++) {
const unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j);
@ -1289,7 +1285,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
}
if (binormals) {
ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size());
ai_assert(tangents.size() == vertices.size());
ai_assert(binormals->size() == vertices.size());
out_mesh->mTangents = new aiVector3D[vertices.size()];
out_mesh->mBitangents = new aiVector3D[vertices.size()];
@ -1542,10 +1539,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
aiBone *bone = nullptr;
if (bone_map.count(deformer_name)) {
ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
ASSIMP_LOG_VERBOSE_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
bone = bone_map[deformer_name];
} else {
ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
ASSIMP_LOG_VERBOSE_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
bone = new aiBone();
bone->mName = bone_name;
@ -2719,7 +2716,7 @@ void FBXConverter::GenerateNodeAnimations(std::vector<aiNodeAnim *> &node_anims,
if (doc.Settings().optimizeEmptyAnimationCurves &&
IsRedundantAnimationData(target, comp, (chain[i]->second))) {
FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name());
FBXImporter::LogVerboseDebug("dropping redundant animation channel for node " + target.Name());
continue;
}
@ -3164,7 +3161,8 @@ FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<c
}
const AnimationCurve *const curve = kv.second;
ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size());
ai_assert(curve->GetKeys().size() == curve->GetValues().size());
ai_assert(curve->GetKeys().size());
//get values within the start/stop time window
std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
@ -3315,6 +3313,7 @@ void FBXConverter::InterpolateKeys(aiQuatKey *valOut, const KeyTimeList &keys, c
// http://www.3dkingdoms.com/weekly/weekly.php?a=36
if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) {
quat.Conjugate();
quat.w = -quat.w;
}
lastq = quat;
@ -3401,7 +3400,8 @@ void FBXConverter::ConvertGlobalSettings() {
mSceneOut->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign());
mSceneOut->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis());
mSceneOut->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign());
mSceneOut->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor());
//const double unitScaleFactor = (double)doc.GlobalSettings().UnitScaleFactor();
mSceneOut->mMetaData->Set(8, "UnitScaleFactor", doc.GlobalSettings().UnitScaleFactor());
mSceneOut->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor());
mSceneOut->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor());
mSceneOut->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode());
@ -3465,7 +3465,7 @@ void FBXConverter::TransferDataToScene() {
}
}
void FBXConverter::ConvertOrphantEmbeddedTextures() {
void FBXConverter::ConvertOrphanedEmbeddedTextures() {
// in C++14 it could be:
// for (auto&& [id, object] : objects)
for (auto &&id_and_object : doc.Objects()) {

View File

@ -220,8 +220,8 @@ private:
* each output vertex the DOM index it maps to.
*/
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
aiNode *parent = NULL, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
std::vector<unsigned int> *outputVertStartIndices = NULL);
aiNode *parent = nullptr, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
std::vector<unsigned int> *outputVertStartIndices = nullptr);
// ------------------------------------------------------------------------------------------------
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
@ -412,7 +412,7 @@ private:
// ------------------------------------------------------------------------------------------------
// FBX file could have embedded textures not connected to anything
void ConvertOrphantEmbeddedTextures();
void ConvertOrphanedEmbeddedTextures();
private:
// 0: not assigned yet, others: index is value - 1

View File

@ -55,6 +55,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXDocumentUtil.h"
#include "FBXProperties.h"
#include <assimp/DefaultLogger.hpp>
#include <memory>
#include <functional>
#include <map>
@ -219,7 +221,7 @@ const Object* LazyObject::Get(bool dieOnError)
if(!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_ERROR(ex.what());
}
return NULL;
return nullptr;
}
if (!object.get()) {
@ -264,6 +266,8 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
: settings(settings)
, parser(parser)
{
ASSIMP_LOG_DEBUG("Creating FBX Document");
// Cannot use array default initialization syntax because vc8 fails on it
for (auto &timeStamp : creationTimeStamp) {
timeStamp = 0;
@ -308,6 +312,7 @@ void Document::ReadHeader() {
const Scope& shead = *ehead->Compound();
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
ASSIMP_LOG_DEBUG_F("FBX Version: ", fbxVersion);
// While we may have some success with newer files, we don't support
// the older 6.n fbx format
@ -462,7 +467,7 @@ void Document::ReadPropertyTemplates()
const Element *Properties70 = (*innerSc)["Properties70"];
if(Properties70) {
std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
*Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
*Properties70, std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable *>(nullptr))
);
templates[oname+"."+pname] = props;

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