replace NULL and avoid ai_assert with more than 2 tests.
commit
6205af4efb
|
@ -1,2 +1,3 @@
|
|||
patreon: assimp
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
|
||||
open_collective: assimp
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -7,40 +7,53 @@ on:
|
|||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: configure
|
||||
run: cmake CMakeLists.txt
|
||||
- name: build
|
||||
run: cmake --build .
|
||||
- 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 && ./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
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: configure
|
||||
run: cmake CMakeLists.txt
|
||||
- name: build
|
||||
run: cmake --build . --config Release
|
||||
- name: test
|
||||
run: |
|
||||
cd bin\Release
|
||||
.\unit
|
||||
run: cd build/bin && ./unit
|
||||
shell: bash
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
23
Readme.md
23
Readme.md
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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_SHARED_LIBRARY_SUFFIX@")
|
||||
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_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}"
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -5,8 +5,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,
|
||||
|
@ -43,17 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file Implementation of the 3ds importer class */
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
// internal headers
|
||||
#include "3DSLoader.h"
|
||||
#include "Common/TargetAnimation.h"
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -61,8 +58,7 @@ static const unsigned int NotSet = 0xcdcdcdcd;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup final material indices, generae a default material if necessary
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial()
|
||||
{
|
||||
void Discreet3DSImporter::ReplaceDefaultMaterial() {
|
||||
// Try to find an existing material that matches the
|
||||
// typical default material setting:
|
||||
// - no textures
|
||||
|
@ -70,8 +66,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
// NOTE: This is here to workaround the fact that some
|
||||
// exporters are writing a default material, too.
|
||||
unsigned int idx(NotSet);
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
|
||||
std::string s = mScene->mMaterials[i].mName;
|
||||
for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
*it = static_cast<char>(::tolower(*it));
|
||||
|
@ -89,8 +84,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
|
||||
{
|
||||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
|
||||
continue;
|
||||
}
|
||||
idx = i;
|
||||
|
@ -104,29 +98,23 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
unsigned int cnt = 0;
|
||||
for (std::vector<D3DS::Mesh>::iterator
|
||||
i = mScene->mMeshes.begin();
|
||||
i != mScene->mMeshes.end();++i)
|
||||
{
|
||||
i != mScene->mMeshes.end(); ++i) {
|
||||
for (std::vector<unsigned int>::iterator
|
||||
a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a) {
|
||||
// NOTE: The additional check seems to be necessary,
|
||||
// some exporters seem to generate invalid data here
|
||||
if (0xcdcdcdcd == (*a))
|
||||
{
|
||||
if (0xcdcdcdcd == (*a)) {
|
||||
(*a) = idx;
|
||||
++cnt;
|
||||
}
|
||||
else if ( (*a) >= mScene->mMaterials.size())
|
||||
{
|
||||
} else if ((*a) >= mScene->mMaterials.size()) {
|
||||
(*a) = idx;
|
||||
ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnt && idx == mScene->mMaterials.size())
|
||||
{
|
||||
if (cnt && idx == mScene->mMaterials.size()) {
|
||||
// We need to create our own default material
|
||||
D3DS::Material sMat("%%%DEFAULT");
|
||||
sMat.mDiffuse = aiColor3D(0.3f, 0.3f, 0.3f);
|
||||
|
@ -138,20 +126,15 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
||||
{
|
||||
for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
void Discreet3DSImporter::CheckIndices(D3DS::Mesh &sMesh) {
|
||||
for (std::vector<D3DS::Face>::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end(); ++i) {
|
||||
// check whether all indices are in range
|
||||
for (unsigned int a = 0; a < 3;++a)
|
||||
{
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a) {
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size() - 1;
|
||||
}
|
||||
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
|
||||
{
|
||||
if (!sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) {
|
||||
ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size() - 1;
|
||||
}
|
||||
|
@ -161,8 +144,7 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate out unique verbose format representation
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
||||
{
|
||||
void Discreet3DSImporter::MakeUnique(D3DS::Mesh &sMesh) {
|
||||
// TODO: really necessary? I don't think. Just a waste of memory and time
|
||||
// to do it now in a separate buffer.
|
||||
|
||||
|
@ -172,13 +154,11 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
|||
if (sMesh.mTexCoords.size())
|
||||
vNew2.resize(sMesh.mFaces.size() * 3);
|
||||
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size(); ++i) {
|
||||
D3DS::Face &face = sMesh.mFaces[i];
|
||||
|
||||
// Positions
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
vNew[base] = sMesh.mPositions[face.mIndices[a]];
|
||||
if (sMesh.mTexCoords.size())
|
||||
vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
|
||||
|
@ -192,8 +172,7 @@ void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS texture to texture keys in an aiMaterial
|
||||
void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
||||
{
|
||||
void CopyTexture(aiMaterial &mat, D3DS::Texture &texture, aiTextureType type) {
|
||||
// Setup the texture name
|
||||
aiString tex;
|
||||
tex.Set(texture.mMapName);
|
||||
|
@ -210,8 +189,7 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
|||
|
||||
// Mirroring - double the scaling values
|
||||
// FIXME: this is not really correct ...
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror)
|
||||
{
|
||||
if (texture.mMapMode == aiTextureMapMode_Mirror) {
|
||||
texture.mScaleU *= 2.0;
|
||||
texture.mScaleV *= 2.0;
|
||||
texture.mOffsetU /= 2.0;
|
||||
|
@ -225,12 +203,10 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a 3DS material to an aiMaterial
|
||||
void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
|
||||
aiMaterial& mat)
|
||||
{
|
||||
aiMaterial &mat) {
|
||||
// NOTE: Pass the background image to the viewer by bypassing the
|
||||
// material system. This is an evil hack, never do it again!
|
||||
if (0 != mBackgroundImage.length() && bHasBG)
|
||||
{
|
||||
if (0 != mBackgroundImage.length() && bHasBG) {
|
||||
aiString tex;
|
||||
tex.Set(mBackgroundImage);
|
||||
mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||
|
@ -256,14 +232,10 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
|
||||
// Phong shininess and shininess strength
|
||||
if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading)
|
||||
{
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
|
||||
{
|
||||
D3DS::Discreet3DS::Metal == oldMat.mShading) {
|
||||
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) {
|
||||
oldMat.mShading = D3DS::Discreet3DS::Gouraud;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mat.AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.AddProperty(&oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
}
|
||||
|
@ -276,43 +248,45 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
mat.AddProperty<ai_real>(&oldMat.mBumpHeight, 1, AI_MATKEY_BUMPSCALING);
|
||||
|
||||
// Two sided rendering?
|
||||
if (oldMat.mTwoSided)
|
||||
{
|
||||
if (oldMat.mTwoSided) {
|
||||
int i = 1;
|
||||
mat.AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
// Shading mode
|
||||
aiShadingMode eShading = aiShadingMode_NoShading;
|
||||
switch (oldMat.mShading)
|
||||
{
|
||||
switch (oldMat.mShading) {
|
||||
case D3DS::Discreet3DS::Flat:
|
||||
eShading = aiShadingMode_Flat; break;
|
||||
eShading = aiShadingMode_Flat;
|
||||
break;
|
||||
|
||||
// I don't know what "Wire" shading should be,
|
||||
// assume it is simple lambertian diffuse shading
|
||||
case D3DS::Discreet3DS::Wire:
|
||||
{
|
||||
case D3DS::Discreet3DS::Wire: {
|
||||
// Set the wireframe flag
|
||||
unsigned int iWire = 1;
|
||||
mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
|
||||
case D3DS::Discreet3DS::Gouraud:
|
||||
eShading = aiShadingMode_Gouraud; break;
|
||||
eShading = aiShadingMode_Gouraud;
|
||||
break;
|
||||
|
||||
// assume cook-torrance shading for metals.
|
||||
case D3DS::Discreet3DS::Phong:
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
eShading = aiShadingMode_Phong;
|
||||
break;
|
||||
|
||||
case D3DS::Discreet3DS::Metal:
|
||||
eShading = aiShadingMode_CookTorrance; break;
|
||||
eShading = aiShadingMode_CookTorrance;
|
||||
break;
|
||||
|
||||
// FIX to workaround a warning with GCC 4 who complained
|
||||
// about a missing case Blinn: here - Blinn isn't a valid
|
||||
// value in the 3DS Loader, it is just needed for ASE
|
||||
case D3DS::Discreet3DS::Blinn:
|
||||
eShading = aiShadingMode_Blinn; break;
|
||||
eShading = aiShadingMode_Blinn;
|
||||
break;
|
||||
}
|
||||
int eShading_ = static_cast<int>(eShading);
|
||||
mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
@ -355,8 +329,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Split meshes by their materials and generate output aiMesh'es
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertMeshes(aiScene *pcOut) {
|
||||
std::vector<aiMesh *> avOutMeshes;
|
||||
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
|
||||
|
||||
|
@ -371,13 +344,11 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
unsigned int iNum = 0;
|
||||
for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a,++iNum)
|
||||
{
|
||||
a != (*i).mFaceMaterials.end(); ++a, ++iNum) {
|
||||
aiSplit[*a].push_back(iNum);
|
||||
}
|
||||
// now generate submeshes
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
|
||||
{
|
||||
for (unsigned int p = 0; p < mScene->mMaterials.size(); ++p) {
|
||||
if (aiSplit[p].empty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -402,20 +373,17 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
|
||||
meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
|
||||
meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
|
||||
if ((*i).mTexCoords.size())
|
||||
{
|
||||
if ((*i).mTexCoords.size()) {
|
||||
meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
|
||||
}
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
|
||||
{
|
||||
for (unsigned int q = 0, base = 0; q < aiSplit[p].size(); ++q) {
|
||||
unsigned int index = aiSplit[p][q];
|
||||
aiFace &face = meshOut->mFaces[q];
|
||||
|
||||
face.mIndices = new unsigned int[3];
|
||||
face.mNumIndices = 3;
|
||||
|
||||
for (unsigned int a = 0; a < 3;++a,++base)
|
||||
{
|
||||
for (unsigned int a = 0; a < 3; ++a, ++base) {
|
||||
unsigned int idx = (*i).mFaces[index].mIndices[a];
|
||||
meshOut->mVertices[base] = (*i).mPositions[idx];
|
||||
meshOut->mNormals[base] = (*i).mNormals[idx];
|
||||
|
@ -445,24 +413,21 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Add a node to the scenegraph and setup its final transformation
|
||||
void Discreet3DSImporter::AddNodeToGraph(aiScene *pcSOut, aiNode *pcOut,
|
||||
D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
|
||||
{
|
||||
D3DS::Node *pcIn, aiMatrix4x4 & /*absTrafo*/) {
|
||||
std::vector<unsigned int> iArray;
|
||||
iArray.reserve(3);
|
||||
|
||||
aiMatrix4x4 abs;
|
||||
|
||||
// Find all meshes with the same name as the node
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
|
||||
{
|
||||
for (unsigned int a = 0; a < pcSOut->mNumMeshes; ++a) {
|
||||
const D3DS::Mesh *pcMesh = (const D3DS::Mesh *)pcSOut->mMeshes[a]->mColors[0];
|
||||
ai_assert(NULL != pcMesh);
|
||||
ai_assert(nullptr != pcMesh);
|
||||
|
||||
if (pcIn->mName == pcMesh->mName)
|
||||
iArray.push_back(a);
|
||||
}
|
||||
if (!iArray.empty())
|
||||
{
|
||||
if (!iArray.empty()) {
|
||||
// The matrix should be identical for all meshes with the
|
||||
// same name. It HAS to be identical for all meshes .....
|
||||
D3DS::Mesh *imesh = ((D3DS::Mesh *)pcSOut->mMeshes[iArray[0]]->mColors[0]);
|
||||
|
@ -470,7 +435,8 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Compute the inverse of the transformation matrix to move the
|
||||
// vertices back to their relative and local space
|
||||
aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
|
||||
mInv.Inverse();mInvTransposed.Transpose();
|
||||
mInv.Inverse();
|
||||
mInvTransposed.Transpose();
|
||||
aiVector3D pivot = pcIn->vPivot;
|
||||
|
||||
pcOut->mNumMeshes = (unsigned int)iArray.size();
|
||||
|
@ -479,8 +445,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
const unsigned int iIndex = iArray[i];
|
||||
aiMesh *const mesh = pcSOut->mMeshes[iIndex];
|
||||
|
||||
if (mesh->mColors[1] == NULL)
|
||||
{
|
||||
if (mesh->mColors[1] == nullptr) {
|
||||
// Transform the vertices back into their local space
|
||||
// fixme: consider computing normals after this, so we don't need to transform them
|
||||
const aiVector3D *const pvEnd = mesh->mVertices + mesh->mNumVertices;
|
||||
|
@ -492,8 +457,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle negative transformation matrix determinant -> invert vertex x
|
||||
if (imesh->mMat.Determinant() < 0.0f)
|
||||
{
|
||||
if (imesh->mMat.Determinant() < 0.0f) {
|
||||
/* we *must* have normals */
|
||||
for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
|
||||
pvCurrent->x *= -1.f;
|
||||
|
@ -503,16 +467,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// Handle pivot point
|
||||
if (pivot.x || pivot.y || pivot.z)
|
||||
{
|
||||
if (pivot.x || pivot.y || pivot.z) {
|
||||
for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
|
||||
*pvCurrent -= pivot;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
}
|
||||
else
|
||||
} else
|
||||
mesh->mColors[1] = (aiColor4D *)1;
|
||||
|
||||
// Setup the mesh index
|
||||
|
@ -522,15 +484,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// Setup the name of the node
|
||||
// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
|
||||
if (pcIn->mInstanceNumber > 1)
|
||||
{
|
||||
if (pcIn->mInstanceNumber > 1) {
|
||||
char tmp[12];
|
||||
ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
|
||||
std::string tempStr = pcIn->mName + "_inst_";
|
||||
tempStr += tmp;
|
||||
pcOut->mName.Set(tempStr);
|
||||
}
|
||||
else
|
||||
} else
|
||||
pcOut->mName.Set(pcIn->mName);
|
||||
|
||||
// Now build the transformation matrix of the node
|
||||
|
@ -543,26 +503,28 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
pcOut->mTransformation = aiMatrix4x4(pcIn->aRotationKeys[0].mValue.GetMatrix());
|
||||
}
|
||||
else if (pcIn->aCameraRollKeys.size())
|
||||
{
|
||||
} else if (pcIn->aCameraRollKeys.size()) {
|
||||
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(-pcIn->aCameraRollKeys[0].mValue),
|
||||
pcOut->mTransformation);
|
||||
}
|
||||
|
||||
// SCALING
|
||||
aiMatrix4x4 &m = pcOut->mTransformation;
|
||||
if (pcIn->aScalingKeys.size())
|
||||
{
|
||||
if (pcIn->aScalingKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aScalingKeys[0].mValue;
|
||||
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
|
||||
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
|
||||
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
|
||||
m.a1 *= v.x;
|
||||
m.b1 *= v.x;
|
||||
m.c1 *= v.x;
|
||||
m.a2 *= v.y;
|
||||
m.b2 *= v.y;
|
||||
m.c2 *= v.y;
|
||||
m.a3 *= v.z;
|
||||
m.b3 *= v.z;
|
||||
m.c3 *= v.z;
|
||||
}
|
||||
|
||||
// TRANSLATION
|
||||
if (pcIn->aPositionKeys.size())
|
||||
{
|
||||
if (pcIn->aPositionKeys.size()) {
|
||||
const aiVector3D &v = pcIn->aPositionKeys[0].mValue;
|
||||
m.a4 += v.x;
|
||||
m.b4 += v.y;
|
||||
|
@ -572,21 +534,18 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
// Generate animation channels for the node
|
||||
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
|
||||
pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
|
||||
pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
pcIn->aTargetPositionKeys.size() > 1) {
|
||||
aiAnimation *anim = pcSOut->mAnimations[0];
|
||||
ai_assert(nullptr != anim);
|
||||
|
||||
if (pcIn->aCameraRollKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
|
||||
if (pcIn->aCameraRollKeys.size() > 1) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting camera roll track ...");
|
||||
|
||||
// Camera roll keys - in fact they're just rotations
|
||||
// around the camera's z axis. The angles are given
|
||||
// in degrees (and they're clockwise).
|
||||
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size(); ++i) {
|
||||
aiQuatKey &q = pcIn->aRotationKeys[i];
|
||||
aiFloatKey &f = pcIn->aCameraRollKeys[i];
|
||||
|
||||
|
@ -599,7 +558,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
#if 0
|
||||
if (pcIn->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("3DS: Converting target track ...");
|
||||
|
||||
// Camera or spot light - need to convert the separate
|
||||
// target position channel to our representation
|
||||
|
@ -655,8 +614,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
nda->mNodeName.Set(pcIn->mName);
|
||||
|
||||
// POSITION keys
|
||||
if (pcIn->aPositionKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aPositionKeys.size() > 0) {
|
||||
nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
|
||||
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
|
||||
::memcpy(nda->mPositionKeys, &pcIn->aPositionKeys[0],
|
||||
|
@ -664,15 +622,13 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// ROTATION keys
|
||||
if (pcIn->aRotationKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aRotationKeys.size() > 0) {
|
||||
nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
|
||||
nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
|
||||
|
||||
// Rotations are quaternion offsets
|
||||
aiQuaternion abs1;
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
|
||||
{
|
||||
for (unsigned int n = 0; n < nda->mNumRotationKeys; ++n) {
|
||||
const aiQuatKey &q = pcIn->aRotationKeys[n];
|
||||
|
||||
abs1 = (n ? abs1 * q.mValue : q.mValue);
|
||||
|
@ -682,8 +638,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
}
|
||||
|
||||
// SCALING keys
|
||||
if (pcIn->aScalingKeys.size() > 0)
|
||||
{
|
||||
if (pcIn->aScalingKeys.size() > 0) {
|
||||
nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
|
||||
nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
|
||||
::memcpy(nda->mScalingKeys, &pcIn->aScalingKeys[0],
|
||||
|
@ -697,8 +652,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// Recursively process all children
|
||||
const unsigned int size = static_cast<unsigned int>(pcIn->mChildren.size());
|
||||
for (unsigned int i = 0; i < size;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
pcOut->mChildren[i] = new aiNode();
|
||||
pcOut->mChildren[i]->mParent = pcOut;
|
||||
AddNodeToGraph(pcSOut, pcOut->mChildren[i], pcIn->mChildren[i], abs);
|
||||
|
@ -707,16 +661,14 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find out how many node animation channels we'll have finally
|
||||
void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
||||
{
|
||||
void CountTracks(D3DS::Node *node, unsigned int &cnt) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// We will never generate more than one channel for a node, so
|
||||
// this is rather easy here.
|
||||
|
||||
if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
|
||||
node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
|
||||
node->aTargetPositionKeys.size() > 1)
|
||||
{
|
||||
node->aTargetPositionKeys.size() > 1) {
|
||||
++cnt;
|
||||
|
||||
// account for the additional channel for the camera/spotlight target position
|
||||
|
@ -730,11 +682,9 @@ void CountTracks(D3DS::Node* node, unsigned int& cnt)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Generate the output node graph
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
|
||||
pcOut->mRootNode = new aiNode();
|
||||
if (0 == mRootNode->mChildren.size())
|
||||
{
|
||||
if (0 == mRootNode->mChildren.size()) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// It seems the file is so messed up that it has not even a hierarchy.
|
||||
// generate a flat hiearachy which looks like this:
|
||||
|
@ -755,8 +705,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
|
||||
// Build dummy nodes for all meshes
|
||||
unsigned int a = 0;
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcOut->mNumMeshes; ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
pcNode->mMeshes = new unsigned int[1];
|
||||
|
@ -768,8 +717,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// Build dummy nodes for all cameras
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mCameras.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
|
@ -778,24 +726,20 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// Build dummy nodes for all lights
|
||||
for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)mScene->mLights.size(); ++i, ++a) {
|
||||
aiNode *pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
|
||||
pcNode->mParent = pcOut->mRootNode;
|
||||
|
||||
// Build a name for the node
|
||||
pcNode->mName = mScene->mLights[i]->mName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// First of all: find out how many scaling, rotation and translation
|
||||
// animation tracks we'll have afterwards
|
||||
unsigned int numChannel = 0;
|
||||
CountTracks(mRootNode, numChannel);
|
||||
|
||||
if (numChannel)
|
||||
{
|
||||
if (numChannel) {
|
||||
// Allocate a primary animation channel
|
||||
pcOut->mNumAnimations = 1;
|
||||
pcOut->mAnimations = new aiAnimation *[1];
|
||||
|
@ -814,37 +758,34 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
}
|
||||
|
||||
// We used the first and second vertex color set to store some temporary values so we need to cleanup here
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
|
||||
{
|
||||
pcOut->mMeshes[a]->mColors[0] = NULL;
|
||||
pcOut->mMeshes[a]->mColors[1] = NULL;
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) {
|
||||
pcOut->mMeshes[a]->mColors[0] = nullptr;
|
||||
pcOut->mMeshes[a]->mColors[1] = nullptr;
|
||||
}
|
||||
|
||||
pcOut->mRootNode->mTransformation = aiMatrix4x4(
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, -1.f, 0.f, 0.f,
|
||||
0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
|
||||
0.f, 0.f, 0.f, 1.f) *
|
||||
pcOut->mRootNode->mTransformation;
|
||||
|
||||
// If the root node is unnamed name it "<3DSRoot>"
|
||||
if (::strstr(pcOut->mRootNode->mName.data, "UNNAMED") ||
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
|
||||
{
|
||||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')) {
|
||||
pcOut->mRootNode->mName.Set("<3DSRoot>");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert all meshes in the scene and generate the final output scene.
|
||||
void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ConvertScene(aiScene *pcOut) {
|
||||
// Allocate enough storage for all output materials
|
||||
pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
|
||||
pcOut->mMaterials = new aiMaterial *[pcOut->mNumMaterials];
|
||||
|
||||
// ... and convert the 3DS materials to aiMaterial's
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcOut->mNumMaterials; ++i) {
|
||||
aiMaterial *pcNew = new aiMaterial();
|
||||
ConvertMaterial(mScene->mMaterials[i], *pcNew);
|
||||
pcOut->mMaterials[i] = pcNew;
|
||||
|
@ -855,16 +796,14 @@ void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
|
|||
|
||||
// Now copy all light sources to the output scene
|
||||
pcOut->mNumLights = (unsigned int)mScene->mLights.size();
|
||||
if (pcOut->mNumLights)
|
||||
{
|
||||
if (pcOut->mNumLights) {
|
||||
pcOut->mLights = new aiLight *[pcOut->mNumLights];
|
||||
::memcpy(pcOut->mLights, &mScene->mLights[0], sizeof(void *) * pcOut->mNumLights);
|
||||
}
|
||||
|
||||
// Now copy all cameras to the output scene
|
||||
pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
|
||||
if (pcOut->mNumCameras)
|
||||
{
|
||||
if (pcOut->mNumCameras) {
|
||||
pcOut->mCameras = new aiCamera *[pcOut->mNumCameras];
|
||||
::memcpy(pcOut->mCameras, &mScene->mCameras[0], sizeof(void *) * pcOut->mNumCameras);
|
||||
}
|
|
@ -43,16 +43,16 @@ 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>
|
||||
|
||||
|
@ -70,14 +70,13 @@ namespace {
|
|||
// 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
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef,
|
||||
SIZE_OFFSET = 2
|
||||
};
|
||||
public:
|
||||
|
||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
||||
: writer(writer)
|
||||
{
|
||||
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);
|
||||
|
@ -99,7 +98,6 @@ namespace {
|
|||
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|.
|
||||
|
@ -149,12 +147,11 @@ namespace {
|
|||
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*/)
|
||||
{
|
||||
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));
|
||||
|
@ -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);
|
||||
|
@ -276,8 +269,7 @@ 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];
|
||||
|
@ -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,
|
||||
|
@ -441,7 +429,6 @@ void Discreet3DSExporter::WriteMeshes()
|
|||
const std::string &name = GetMeshName(mesh, mesh_idx, node);
|
||||
WriteString(name);
|
||||
|
||||
|
||||
// TRIMESH chunk
|
||||
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
||||
|
||||
|
@ -524,8 +511,7 @@ 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);
|
||||
WriteString(name);
|
||||
|
@ -577,6 +563,5 @@ void Discreet3DSExporter::WritePercentChunk(double f) {
|
|||
writer.PutF8(f);
|
||||
}
|
||||
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -441,12 +441,31 @@ 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)),
|
||||
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)),
|
||||
|
@ -465,6 +484,7 @@ struct Material {
|
|||
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);
|
|
@ -5,8 +5,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,
|
||||
|
@ -47,15 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* http://www.the-labs.com/Blender/3DS-details.html
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
||||
#include "3DSLoader.h"
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -72,7 +69,6 @@ static const aiImporterDesc desc = {
|
|||
"3ds prj"
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Begins a new parsing block
|
||||
// - Reads the current chunk and validates it
|
||||
|
@ -88,8 +84,7 @@ static const aiImporterDesc desc = {
|
|||
if (chunkSize <= 0) \
|
||||
continue; \
|
||||
const unsigned int oldReadLimit = stream->SetReadLimit( \
|
||||
stream->GetCurrentPos() + chunkSize); \
|
||||
|
||||
stream->GetCurrentPos() + chunkSize);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// End a parsing block
|
||||
|
@ -103,15 +98,8 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
Discreet3DSImporter::Discreet3DSImporter()
|
||||
: stream()
|
||||
, mLastNodeIndex()
|
||||
, mCurrentNode()
|
||||
, mRootNode()
|
||||
, mScene()
|
||||
, mMasterScale()
|
||||
, bHasBG()
|
||||
, bIsPrj() {
|
||||
Discreet3DSImporter::Discreet3DSImporter() :
|
||||
stream(), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -141,23 +129,20 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader registry entry
|
||||
const aiImporterDesc* Discreet3DSImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *Discreet3DSImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties
|
||||
void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||
// nothing to be done for the moment
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void Discreet3DSImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
|
||||
|
||||
// We should have at least one chunk
|
||||
|
@ -177,7 +162,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
mRootNode = mCurrentNode;
|
||||
mRootNode->mHierarchyPos = -1;
|
||||
mRootNode->mHierarchyIndex = -1;
|
||||
mRootNode->mParent = NULL;
|
||||
mRootNode->mParent = nullptr;
|
||||
mMasterScale = 1.0f;
|
||||
mBackgroundImage = "";
|
||||
bHasBG = false;
|
||||
|
@ -200,7 +185,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
ComputeNormalsWithSmoothingsGroups<D3DS::Face>(mesh);
|
||||
}
|
||||
|
||||
// Replace all occurences of the default material with a
|
||||
// Replace all occurrences of the default material with a
|
||||
// valid material. Generate it if no material containing
|
||||
// DEFAULT in its name has been found in the file
|
||||
ReplaceDefaultMaterial();
|
||||
|
@ -227,11 +212,12 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Applies a master-scaling factor to the imported scene
|
||||
void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
|
||||
{
|
||||
void Discreet3DSImporter::ApplyMasterScale(aiScene *pScene) {
|
||||
// There are some 3DS files with a zero scaling factor
|
||||
if (!mMasterScale)mMasterScale = 1.0f;
|
||||
else mMasterScale = 1.0f / mMasterScale;
|
||||
if (!mMasterScale)
|
||||
mMasterScale = 1.0f;
|
||||
else
|
||||
mMasterScale = 1.0f / mMasterScale;
|
||||
|
||||
// Construct an uniform scaling matrix and multiply with it
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
|
@ -245,8 +231,7 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a new chunk from the file
|
||||
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk *pcOut) {
|
||||
ai_assert(pcOut != nullptr);
|
||||
|
||||
pcOut->Flag = stream->GetI2();
|
||||
|
@ -263,8 +248,7 @@ void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Skip a chunk
|
||||
void Discreet3DSImporter::SkipChunk()
|
||||
{
|
||||
void Discreet3DSImporter::SkipChunk() {
|
||||
Discreet3DS::Chunk psChunk;
|
||||
ReadChunk(&psChunk);
|
||||
|
||||
|
@ -274,13 +258,11 @@ void Discreet3DSImporter::SkipChunk()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Process the primary chunk of the file
|
||||
void Discreet3DSImporter::ParseMainChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMainChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
|
||||
case Discreet3DS::CHUNK_PRJ:
|
||||
bIsPrj = true;
|
||||
|
@ -295,13 +277,11 @@ void Discreet3DSImporter::ParseMainChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseEditorChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseEditorChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_OBJMESH:
|
||||
|
||||
ParseObjectChunk();
|
||||
|
@ -314,36 +294,31 @@ void Discreet3DSImporter::ParseEditorChunk()
|
|||
ParseKeyframeChunk();
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_VERSION:
|
||||
{
|
||||
case Discreet3DS::CHUNK_VERSION: {
|
||||
// print the version number
|
||||
char buff[10];
|
||||
ASSIMP_itoa10(buff, stream->GetI2());
|
||||
ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseObjectChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseObjectChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_OBJBLOCK:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_OBJBLOCK: {
|
||||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
|
||||
// Get the name of the geometry object
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
ParseChunk(sz, cnt);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_MATERIAL:
|
||||
|
||||
|
@ -357,24 +332,22 @@ void Discreet3DSImporter::ParseObjectChunk()
|
|||
// This is the ambient base color of the scene.
|
||||
// We add it to the ambient color of all materials
|
||||
ParseColorChunk(&mClrAmbient, true);
|
||||
if (is_qnan(mClrAmbient.r))
|
||||
{
|
||||
if (is_qnan(mClrAmbient.r)) {
|
||||
// We failed to read the ambient base color.
|
||||
ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
|
||||
mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_BIT_MAP:
|
||||
{
|
||||
case Discreet3DS::CHUNK_BIT_MAP: {
|
||||
// Specifies the background image. The string should already be
|
||||
// properly 0 terminated but we need to be sure
|
||||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
mBackgroundImage = std::string(sz, cnt);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
|
||||
bHasBG = true;
|
||||
|
@ -389,8 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
||||
{
|
||||
void Discreet3DSImporter::ParseChunk(const char *name, unsigned int num) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// IMPLEMENTATION NOTE;
|
||||
|
@ -399,20 +371,16 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
// to to be able to return valid cameras/lights even if no scenegraph is given.
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRIMESH:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRIMESH: {
|
||||
// this starts a new triangle mesh
|
||||
mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num)));
|
||||
|
||||
// Read mesh chunks
|
||||
ParseMeshChunk();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_LIGHT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_LIGHT: {
|
||||
// This starts a new light
|
||||
aiLight *light = new aiLight();
|
||||
mScene->mLights.push_back(light);
|
||||
|
@ -435,15 +403,13 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
light->mColorSpecular = light->mColorDiffuse;
|
||||
light->mColorAmbient = mClrAmbient;
|
||||
|
||||
if (light->mType == aiLightSource_UNDEFINED)
|
||||
{
|
||||
if (light->mType == aiLightSource_UNDEFINED) {
|
||||
// It must be a point light
|
||||
light->mType = aiLightSource_POINT;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_CAMERA:
|
||||
{
|
||||
case Discreet3DS::CHUNK_CAMERA: {
|
||||
// This starts a new camera
|
||||
aiCamera *camera = new aiCamera();
|
||||
mScene->mCameras.push_back(camera);
|
||||
|
@ -465,8 +431,8 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
|
||||
camera->mLookAt = aiVector3D(0.0, 1.0, 0.0);
|
||||
|
||||
}
|
||||
else camera->mLookAt /= len;
|
||||
} else
|
||||
camera->mLookAt /= len;
|
||||
|
||||
// And finally - the camera rotation angle, in counter clockwise direction
|
||||
const ai_real angle = AI_DEG_TO_RAD(stream->GetF4());
|
||||
|
@ -482,21 +448,19 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
|
|||
// Now check for further subchunks
|
||||
if (!bIsPrj) /* fixme */ {
|
||||
ParseCameraChunk();
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseLightChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseLightChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
aiLight *light = mScene->mLights.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_DL_SPOTLIGHT:
|
||||
// Now we can be sure that the light is a spot light
|
||||
light->mType = aiLightSource_SPOT;
|
||||
|
@ -537,14 +501,12 @@ void Discreet3DSImporter::ParseLightChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseCameraChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseCameraChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
aiCamera *camera = mScene->mCameras.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
// near and far clip plane
|
||||
case Discreet3DS::CHUNK_CAM_RANGES:
|
||||
camera->mClipPlaneNear = stream->GetF4();
|
||||
|
@ -556,13 +518,11 @@ void Discreet3DSImporter::ParseCameraChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseKeyframeChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseKeyframeChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRACKCAMTGT:
|
||||
case Discreet3DS::CHUNK_TRACKSPOTL:
|
||||
case Discreet3DS::CHUNK_TRACKCAMERA:
|
||||
|
@ -580,8 +540,7 @@ void Discreet3DSImporter::ParseKeyframeChunk()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Little helper function for ParseHierarchyChunk
|
||||
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
|
||||
{
|
||||
void Discreet3DSImporter::InverseNodeSearch(D3DS::Node *pcNode, D3DS::Node *pcCurrent) {
|
||||
if (!pcCurrent) {
|
||||
mRootNode->push_back(pcNode);
|
||||
return;
|
||||
|
@ -590,8 +549,8 @@ void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCur
|
|||
if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos) {
|
||||
if (pcCurrent->mParent) {
|
||||
pcCurrent->mParent->push_back(pcNode);
|
||||
}
|
||||
else pcCurrent->push_back(pcNode);
|
||||
} else
|
||||
pcCurrent->push_back(pcNode);
|
||||
return;
|
||||
}
|
||||
return InverseNodeSearch(pcNode, pcCurrent->mParent);
|
||||
|
@ -617,15 +576,13 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Binary predicate for std::unique()
|
||||
template <class T>
|
||||
bool KeyUniqueCompare(const T& first, const T& second)
|
||||
{
|
||||
bool KeyUniqueCompare(const T &first, const T &second) {
|
||||
return first.mTime == second.mTime;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Skip some additional import data.
|
||||
void Discreet3DSImporter::SkipTCBInfo()
|
||||
{
|
||||
void Discreet3DSImporter::SkipTCBInfo() {
|
||||
unsigned int flags = stream->GetI2();
|
||||
|
||||
if (!flags) {
|
||||
|
@ -655,13 +612,11 @@ void Discreet3DSImporter::SkipTCBInfo()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read hierarchy and keyframe info
|
||||
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
||||
{
|
||||
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_TRACKOBJNAME:
|
||||
|
||||
// This is the name of the object to which the track applies. The chunk also
|
||||
|
@ -672,7 +627,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
unsigned int cnt = 0;
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
|
||||
while (stream->GetI1())++cnt;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
std::string name = std::string(sz, cnt);
|
||||
|
||||
// Now find out whether we have this node already (target animation channels
|
||||
|
@ -680,11 +636,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
D3DS::Node *pcNode = FindNode(mRootNode, name);
|
||||
int instanceNumber = 1;
|
||||
|
||||
if ( pcNode)
|
||||
{
|
||||
if (pcNode) {
|
||||
// if the source is not a CHUNK_TRACKINFO block it won't be an object instance
|
||||
if (parent != Discreet3DS::CHUNK_TRACKINFO)
|
||||
{
|
||||
if (parent != Discreet3DS::CHUNK_TRACKINFO) {
|
||||
mCurrentNode = pcNode;
|
||||
break;
|
||||
}
|
||||
|
@ -708,14 +662,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
// add to the parent of the last touched node
|
||||
mCurrentNode->mParent->push_back(pcNode);
|
||||
mLastNodeIndex++;
|
||||
}
|
||||
else if(hierarchy >= mLastNodeIndex) {
|
||||
} else if (hierarchy >= mLastNodeIndex) {
|
||||
|
||||
// place it at the current position in the hierarchy
|
||||
mCurrentNode->push_back(pcNode);
|
||||
mLastNodeIndex = hierarchy;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// need to go back to the specified position in the hierarchy.
|
||||
InverseNodeSearch(pcNode, mCurrentNode);
|
||||
mLastNodeIndex++;
|
||||
|
@ -730,7 +682,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
// This is the "real" name of a $$$DUMMY object
|
||||
{
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1());
|
||||
while (stream->GetI1())
|
||||
;
|
||||
|
||||
// If object name is DUMMY, take this one instead
|
||||
if (mCurrentNode->mName == "$$$DUMMY") {
|
||||
|
@ -742,8 +695,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
|
||||
case Discreet3DS::CHUNK_TRACKPIVOT:
|
||||
|
||||
if ( Discreet3DS::CHUNK_TRACKINFO != parent)
|
||||
{
|
||||
if (Discreet3DS::CHUNK_TRACKINFO != parent) {
|
||||
ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
|
||||
break;
|
||||
}
|
||||
|
@ -754,11 +706,9 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
mCurrentNode->vPivot.z = stream->GetF4();
|
||||
break;
|
||||
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// POSITION KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKPOS:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKPOS: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI4();
|
||||
bool sortKeys = false;
|
||||
|
@ -768,8 +718,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
std::vector<aiVectorKey> *l;
|
||||
if (Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent) {
|
||||
l = &mCurrentNode->aTargetPositionKeys;
|
||||
}
|
||||
else l = & mCurrentNode->aPositionKeys;
|
||||
} else
|
||||
l = &mCurrentNode->aPositionKeys;
|
||||
|
||||
l->reserve(numFrames);
|
||||
for (unsigned int i = 0; i < numFrames; ++i) {
|
||||
|
@ -796,14 +746,14 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// CAMERA ROLL KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKROLL:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKROLL: {
|
||||
// roll keys are accepted for cameras only
|
||||
if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
|
||||
ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
|
||||
|
@ -838,24 +788,19 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiFloatKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// CAMERA FOV KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKFOV:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKFOV: {
|
||||
ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
|
||||
"This is not supported");
|
||||
}
|
||||
break;
|
||||
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// ROTATION KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKROTATE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKROTATE: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI4();
|
||||
|
||||
|
@ -894,13 +839,12 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiQuatKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// SCALING KEYFRAME
|
||||
case Discreet3DS::CHUNK_TRACKSCALE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_TRACKSCALE: {
|
||||
stream->IncPtr(10);
|
||||
const unsigned int numFrames = stream->GetI2();
|
||||
stream->IncPtr(2);
|
||||
|
@ -937,8 +881,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
if (sortKeys) {
|
||||
std::stable_sort(l->begin(), l->end());
|
||||
l->erase(std::unique(l->begin(), l->end(), &KeyUniqueCompare<aiVectorKey>), l->end());
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
|
@ -946,18 +890,15 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a face chunk - it contains smoothing groups and material assignments
|
||||
void Discreet3DSImporter::ParseFaceChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseFaceChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// Get the mesh we're currently working on
|
||||
D3DS::Mesh &mMesh = mScene->mMeshes.back();
|
||||
|
||||
// Get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_SMOOLIST:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_SMOOLIST: {
|
||||
// This is the list of smoothing groups - a bitfield for every face.
|
||||
// Up to 32 smoothing groups assigned to a single face.
|
||||
unsigned int num = chunkSize / 4, m = 0;
|
||||
|
@ -967,14 +908,14 @@ void Discreet3DSImporter::ParseFaceChunk()
|
|||
for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin(); m != num; ++i, ++m) {
|
||||
// nth bit is set for nth smoothing group
|
||||
(*i).iSmoothGroup = stream->GetI4();
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_FACEMAT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_FACEMAT: {
|
||||
// at fist an asciiz with the material name
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
while (stream->GetI1());
|
||||
while (stream->GetI1())
|
||||
;
|
||||
|
||||
// find the index of the material
|
||||
unsigned int idx = 0xcdcdcdcd, cnt = 0;
|
||||
|
@ -997,28 +938,25 @@ void Discreet3DSImporter::ParseFaceChunk()
|
|||
// check range
|
||||
if (fidx >= mMesh.mFaceMaterials.size()) {
|
||||
ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
|
||||
} else
|
||||
mMesh.mFaceMaterials[fidx] = idx;
|
||||
}
|
||||
else mMesh.mFaceMaterials[fidx] = idx;
|
||||
}}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a mesh chunk. Here's the actual mesh data
|
||||
void Discreet3DSImporter::ParseMeshChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMeshChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// Get the mesh we're currently working on
|
||||
D3DS::Mesh &mMesh = mScene->mMeshes.back();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_VERTLIST:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_VERTLIST: {
|
||||
// This is the list of all vertices in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mPositions.reserve(num);
|
||||
|
@ -1028,10 +966,9 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
v.y = stream->GetF4();
|
||||
v.z = stream->GetF4();
|
||||
mMesh.mPositions.push_back(v);
|
||||
}}
|
||||
break;
|
||||
case Discreet3DS::CHUNK_TRMATRIX:
|
||||
{
|
||||
}
|
||||
} break;
|
||||
case Discreet3DS::CHUNK_TRMATRIX: {
|
||||
// This is the RLEATIVE transformation matrix of the current mesh. Vertices are
|
||||
// pretransformed by this matrix wonder.
|
||||
mMesh.mMat.a1 = stream->GetF4();
|
||||
|
@ -1046,11 +983,9 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
mMesh.mMat.a4 = stream->GetF4();
|
||||
mMesh.mMat.b4 = stream->GetF4();
|
||||
mMesh.mMat.c4 = stream->GetF4();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAPLIST:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAPLIST: {
|
||||
// This is the list of all UV coords in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mTexCoords.reserve(num);
|
||||
|
@ -1059,11 +994,10 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
v.x = stream->GetF4();
|
||||
v.y = stream->GetF4();
|
||||
mMesh.mTexCoords.push_back(v);
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_FACELIST:
|
||||
{
|
||||
case Discreet3DS::CHUNK_FACELIST: {
|
||||
// This is the list of all faces in the current mesh
|
||||
int num = (int)(uint16_t)stream->GetI2();
|
||||
mMesh.mFaces.reserve(num);
|
||||
|
@ -1084,22 +1018,19 @@ void Discreet3DSImporter::ParseMeshChunk()
|
|||
mMesh.mFaceMaterials.resize(mMesh.mFaces.size(), 0xcdcdcdcd);
|
||||
|
||||
// Larger 3DS files could have multiple FACE chunks here
|
||||
chunkSize = stream->GetRemainingSizeToLimit();
|
||||
chunkSize = (int)stream->GetRemainingSizeToLimit();
|
||||
if (chunkSize > (int)sizeof(Discreet3DS::Chunk))
|
||||
ParseFaceChunk();
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
};
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a 3DS material chunk
|
||||
void Discreet3DSImporter::ParseMaterialChunk()
|
||||
{
|
||||
void Discreet3DSImporter::ParseMaterialChunk() {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_MAT_MATNAME:
|
||||
|
||||
{
|
||||
|
@ -1112,13 +1043,11 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
if (!cnt) {
|
||||
// This may not be, we use the default name instead
|
||||
ASSIMP_LOG_ERROR("3DS: Empty material name");
|
||||
}
|
||||
else mScene->mMaterials.back().mName = std::string(sz,cnt);
|
||||
}
|
||||
break;
|
||||
} else
|
||||
mScene->mMaterials.back().mName = std::string(sz, cnt);
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_DIFFUSE:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_DIFFUSE: {
|
||||
// This is the diffuse material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mDiffuse;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1126,11 +1055,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
|
||||
pc->r = pc->g = pc->b = 1.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SPECULAR:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_SPECULAR: {
|
||||
// This is the specular material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mSpecular;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1138,11 +1066,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
|
||||
pc->r = pc->g = pc->b = 1.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_AMBIENT:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_AMBIENT: {
|
||||
// This is the ambient material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mAmbient;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1150,11 +1077,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
|
||||
pc->r = pc->g = pc->b = 0.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILLUM: {
|
||||
// This is the emissive material color
|
||||
aiColor3D *pc = &mScene->mMaterials.back().mEmissive;
|
||||
ParseColorChunk(pc);
|
||||
|
@ -1162,11 +1088,10 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
// color chunk is invalid. Simply ignore it
|
||||
ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
|
||||
pc->r = pc->g = pc->b = 0.0f;
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_TRANSPARENCY: {
|
||||
// This is the material's transparency
|
||||
ai_real *pcf = &mScene->mMaterials.back().mTransparency;
|
||||
*pcf = ParsePercentageChunk();
|
||||
|
@ -1176,8 +1101,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
*pcf = ai_real(1.0);
|
||||
else
|
||||
*pcf = ai_real(1.0) - *pcf * (ai_real)0xFFFF / ai_real(100.0);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHADING:
|
||||
// This is the material shading mode
|
||||
|
@ -1189,37 +1113,32 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
mScene->mMaterials.back().mTwoSided = true;
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS:
|
||||
{ // This is the shininess of the material
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS: { // This is the shininess of the material
|
||||
ai_real *pcf = &mScene->mMaterials.back().mSpecularExponent;
|
||||
*pcf = ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 0.0;
|
||||
else *pcf *= (ai_real)0xFFFF;
|
||||
}
|
||||
break;
|
||||
else
|
||||
*pcf *= (ai_real)0xFFFF;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
|
||||
{ // This is the shininess strength of the material
|
||||
case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT: { // This is the shininess strength of the material
|
||||
ai_real *pcf = &mScene->mMaterials.back().mShininessStrength;
|
||||
*pcf = ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = ai_real(0.0);
|
||||
else
|
||||
*pcf *= (ai_real)0xffff / ai_real(100.0);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
|
||||
{ // This is the self illumination strength of the material
|
||||
case Discreet3DS::CHUNK_MAT_SELF_ILPCT: { // This is the self illumination strength of the material
|
||||
ai_real f = ParsePercentageChunk();
|
||||
if (is_qnan(f))
|
||||
f = ai_real(0.0);
|
||||
else
|
||||
f *= (ai_real)0xFFFF / ai_real(100.0);
|
||||
mScene->mMaterials.back().mEmissive = aiColor3D(f, f, f);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
// Parse texture chunks
|
||||
case Discreet3DS::CHUNK_MAT_TEXTURE:
|
||||
|
@ -1255,24 +1174,19 @@ void Discreet3DSImporter::ParseMaterialChunk()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
||||
{
|
||||
void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture *pcOut) {
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
switch (chunk.Flag)
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAPFILE:
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_MAPFILE: {
|
||||
// The material name string is already zero-terminated, but we need to be sure ...
|
||||
const char *sz = (const char *)stream->GetPtr();
|
||||
unsigned int cnt = 0;
|
||||
while (stream->GetI1())
|
||||
++cnt;
|
||||
pcOut->mMapName = std::string(sz, cnt);
|
||||
}
|
||||
break;
|
||||
|
||||
} break;
|
||||
|
||||
case Discreet3DS::CHUNK_PERCENTD:
|
||||
// Manually parse the blend factor
|
||||
|
@ -1292,8 +1206,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
case Discreet3DS::CHUNK_MAT_MAP_USCALE:
|
||||
// Texture coordinate scaling in the U direction
|
||||
pcOut->mScaleU = stream->GetF4();
|
||||
if (0.0f == pcOut->mScaleU)
|
||||
{
|
||||
if (0.0f == pcOut->mScaleU) {
|
||||
ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1.");
|
||||
pcOut->mScaleU = 1.0f;
|
||||
}
|
||||
|
@ -1301,8 +1214,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
|
||||
// Texture coordinate scaling in the V direction
|
||||
pcOut->mScaleV = stream->GetF4();
|
||||
if (0.0f == pcOut->mScaleV)
|
||||
{
|
||||
if (0.0f == pcOut->mScaleV) {
|
||||
ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1.");
|
||||
pcOut->mScaleV = 1.0f;
|
||||
}
|
||||
|
@ -1323,8 +1235,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
pcOut->mRotation = -AI_DEG_TO_RAD(stream->GetF4());
|
||||
break;
|
||||
|
||||
case Discreet3DS::CHUNK_MAT_MAP_TILING:
|
||||
{
|
||||
case Discreet3DS::CHUNK_MAT_MAP_TILING: {
|
||||
const uint16_t iFlags = stream->GetI2();
|
||||
|
||||
// Get the mapping mode (for both axes)
|
||||
|
@ -1335,9 +1246,9 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
|
|||
pcOut->mMapMode = aiTextureMapMode_Decal;
|
||||
|
||||
// wrapping in all remaining cases
|
||||
else pcOut->mMapMode = aiTextureMapMode_Wrap;
|
||||
}
|
||||
break;
|
||||
else
|
||||
pcOut->mMapMode = aiTextureMapMode_Wrap;
|
||||
} break;
|
||||
};
|
||||
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
|
@ -1360,9 +1271,8 @@ ai_real Discreet3DSImporter::ParsePercentageChunk() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
|
||||
void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
||||
{
|
||||
ai_assert(out != NULL);
|
||||
void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
|
||||
ai_assert(out != nullptr);
|
||||
|
||||
// error return value
|
||||
const ai_real qnan = get_qnan();
|
||||
|
@ -1375,8 +1285,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
bool bGamma = false;
|
||||
|
||||
// Get the type of the chunk
|
||||
switch(chunk.Flag)
|
||||
{
|
||||
switch (chunk.Flag) {
|
||||
case Discreet3DS::CHUNK_LINRGBF:
|
||||
bGamma = true;
|
||||
|
||||
|
@ -1392,8 +1301,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
|
||||
case Discreet3DS::CHUNK_LINRGBB:
|
||||
bGamma = true;
|
||||
case Discreet3DS::CHUNK_RGBB:
|
||||
{
|
||||
case Discreet3DS::CHUNK_RGBB: {
|
||||
if (sizeof(char) * 3 > diff) {
|
||||
*out = clrError;
|
||||
return;
|
||||
|
@ -1402,8 +1310,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
|
|||
out->r = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
out->g = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
out->b = (ai_real)(uint8_t)stream->GetI1() * invVal;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
// Percentage chunks are accepted, too.
|
||||
case Discreet3DS::CHUNK_PERCENTF:
|
|
@ -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.
|
|
@ -44,13 +44,13 @@ 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"
|
||||
|
@ -83,15 +83,8 @@ void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pSce
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
|
|||
|
||||
writeObjects();
|
||||
|
||||
|
||||
mModelOutput << "</" << XmlTag::resources << ">";
|
||||
mModelOutput << std::endl;
|
||||
writeBuild();
|
||||
|
@ -254,8 +246,18 @@ void D3MFExporter::writeBaseMaterials() {
|
|||
if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
|
||||
hexDiffuseColor.clear();
|
||||
tmp.clear();
|
||||
hexDiffuseColor = "#";
|
||||
// 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);
|
||||
|
@ -264,6 +266,7 @@ void D3MFExporter::writeBaseMaterials() {
|
|||
hexDiffuseColor += tmp;
|
||||
tmp = DecimalToHexa((ai_real)color.a);
|
||||
hexDiffuseColor += tmp;
|
||||
}
|
||||
} else {
|
||||
hexDiffuseColor = "#FFFFFFFF";
|
||||
}
|
||||
|
@ -284,7 +287,7 @@ void D3MFExporter::writeObjects() {
|
|||
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]];
|
||||
|
@ -348,7 +351,7 @@ void D3MFExporter::writeBuild() {
|
|||
mModelOutput << "<" << XmlTag::build << ">" << std::endl;
|
||||
|
||||
for (size_t i = 0; i < mBuildItems.size(); ++i) {
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
|
||||
mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
|
||||
mModelOutput << std::endl;
|
||||
}
|
||||
mModelOutput << "</" << XmlTag::build << ">";
|
||||
|
@ -394,7 +397,6 @@ void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::str
|
|||
zip_entry_close(m_zipArchive);
|
||||
}
|
||||
|
||||
|
||||
} // Namespace D3MF
|
||||
} // Namespace Assimp
|
||||
|
|
@ -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>
|
||||
|
||||
|
@ -73,12 +73,12 @@ public:
|
|||
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){
|
||||
XmlSerializer(XmlReader *xmlReader) :
|
||||
mMeshes(),
|
||||
mMatArray(),
|
||||
mActiveMatGroup(99999999),
|
||||
mMatId2MatArray(),
|
||||
xmlReader(xmlReader) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -314,20 +314,19 @@ private:
|
|||
++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, NULL, 16 ) ) / ai_real(255.0);
|
||||
diffuse.g = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
|
||||
diffuse.b = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
if (7 == len)
|
||||
return true;
|
||||
|
@ -335,7 +334,7 @@ private:
|
|||
++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;
|
||||
}
|
||||
|
@ -346,7 +345,6 @@ private:
|
|||
if (parseColor(color, diffuse)) {
|
||||
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
}
|
||||
aiMaterial *readMaterialDef() {
|
||||
aiMaterial *mat(nullptr);
|
||||
|
@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
|
|||
"3mf"
|
||||
};
|
||||
|
||||
D3MFImporter::D3MFImporter()
|
||||
: BaseImporter() {
|
||||
D3MFImporter::D3MFImporter() :
|
||||
BaseImporter() {
|
||||
// empty
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
||||
|
@ -71,22 +71,18 @@ public:
|
|||
OpcPackageRelationshipReader(XmlReader *xmlReader) {
|
||||
while (xmlReader->read()) {
|
||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
|
||||
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER)
|
||||
{
|
||||
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) {
|
||||
ParseRootNode(xmlReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParseRootNode(XmlReader* xmlReader)
|
||||
{
|
||||
void ParseRootNode(XmlReader *xmlReader) {
|
||||
ParseAttributes(xmlReader);
|
||||
|
||||
while(xmlReader->read())
|
||||
{
|
||||
while (xmlReader->read()) {
|
||||
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
|
||||
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE)
|
||||
{
|
||||
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
|
||||
ParseChildNode(xmlReader);
|
||||
}
|
||||
}
|
||||
|
@ -118,9 +114,8 @@ public:
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||
: mRootStream(nullptr)
|
||||
, mZipArchive() {
|
||||
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 + ".");
|
||||
|
@ -131,12 +126,15 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
|
||||
for (auto &file : fileList) {
|
||||
if (file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
|
||||
//PkgRelationshipReader pkgRelReader(file, archive);
|
||||
ai_assert(mZipArchive->Exists(file.c_str()));
|
||||
if (!mZipArchive->Exists(file.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IOStream *fileStream = mZipArchive->Open(file.c_str());
|
||||
|
||||
if (nullptr == fileStream) {
|
||||
ai_assert(fileStream != nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string rootFile = ReadPackageRootRelationship(fileStream);
|
||||
if (rootFile.size() > 0 && rootFile[0] == '/') {
|
||||
|
@ -147,7 +145,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG(rootFile);
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
|
||||
|
||||
mZipArchive->Close(fileStream);
|
||||
|
||||
|
@ -162,7 +160,6 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
} else {
|
||||
ASSIMP_LOG_WARN_F("Ignored file of unknown type: ", 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
|
||||
|
@ -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);
|
||||
|
|
@ -56,27 +56,20 @@ struct aiMesh;
|
|||
struct aiMaterial;
|
||||
struct aiLight;
|
||||
|
||||
|
||||
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,12 +94,9 @@ public:
|
|||
};
|
||||
|
||||
// Represents an AC3D surface
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: mat (0)
|
||||
, flags (0)
|
||||
{}
|
||||
struct Surface {
|
||||
Surface() :
|
||||
mat(0), flags(0) {}
|
||||
|
||||
unsigned int mat, flags;
|
||||
|
||||
|
@ -115,27 +105,12 @@ public:
|
|||
};
|
||||
|
||||
// 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,
|
||||
Group = 0x2,
|
||||
|
@ -177,9 +152,7 @@ public:
|
|||
float crease;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
|
@ -188,7 +161,6 @@ public:
|
|||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details */
|
||||
|
@ -207,7 +179,6 @@ protected:
|
|||
void SetupProperties(const Importer *pImp);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached*/
|
||||
|
@ -231,7 +202,7 @@ private:
|
|||
std::vector<aiMesh *> &meshes,
|
||||
std::vector<aiMaterial *> &outMaterials,
|
||||
const std::vector<Material> &materials,
|
||||
aiNode* parent = NULL);
|
||||
aiNode *parent = nullptr);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
|
@ -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
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
|
@ -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
|
|
@ -51,15 +51,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// internal headers
|
||||
#include "ASELoader.h"
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include "Common/TargetAnimation.h"
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -84,12 +84,8 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ASEImporter::ASEImporter()
|
||||
: mParser()
|
||||
, mBuffer()
|
||||
, pcScene()
|
||||
, configRecomputeNormals()
|
||||
, noSkeletonMesh() {
|
||||
ASEImporter::ASEImporter() :
|
||||
mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -126,7 +122,9 @@ const aiImporterDesc* ASEImporter::GetInfo () const {
|
|||
// Setup configuration options
|
||||
void ASEImporter::SetupProperties(const Importer *pImp) {
|
||||
configRecomputeNormals = (pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
|
||||
AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS, 1) ?
|
||||
true :
|
||||
false);
|
||||
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
|
||||
}
|
||||
|
@ -226,17 +224,20 @@ void ASEImporter::InternReadFile( const std::string& pFile,
|
|||
// into one huge list.
|
||||
//------------------------------------------------------------------
|
||||
std::vector<BaseNode *> nodes;
|
||||
nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
|
||||
+ mParser->m_vCameras.size() + mParser->m_vDummies.size());
|
||||
nodes.reserve(mParser->m_vMeshes.size() + mParser->m_vLights.size() + mParser->m_vCameras.size() + mParser->m_vDummies.size());
|
||||
|
||||
// Lights
|
||||
for (auto &light : mParser->m_vLights)nodes.push_back(&light);
|
||||
for (auto &light : mParser->m_vLights)
|
||||
nodes.push_back(&light);
|
||||
// Cameras
|
||||
for (auto &camera : mParser->m_vCameras)nodes.push_back(&camera);
|
||||
for (auto &camera : mParser->m_vCameras)
|
||||
nodes.push_back(&camera);
|
||||
// Meshes
|
||||
for (auto &mesh : mParser->m_vMeshes)nodes.push_back(&mesh);
|
||||
for (auto &mesh : mParser->m_vMeshes)
|
||||
nodes.push_back(&mesh);
|
||||
// Dummies
|
||||
for (auto &dummy : mParser->m_vDummies)nodes.push_back(&dummy);
|
||||
for (auto &dummy : mParser->m_vDummies)
|
||||
nodes.push_back(&dummy);
|
||||
|
||||
// build the final node graph
|
||||
BuildNodes(nodes);
|
||||
|
@ -263,9 +264,8 @@ void ASEImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::GenerateDefaultMaterial()
|
||||
{
|
||||
ai_assert(NULL != mParser);
|
||||
void ASEImporter::GenerateDefaultMaterial() {
|
||||
ai_assert(nullptr != mParser);
|
||||
|
||||
bool bHas = false;
|
||||
for (std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin(); i != mParser->m_vMeshes.end(); ++i) {
|
||||
|
@ -288,8 +288,7 @@ void ASEImporter::GenerateDefaultMaterial()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
||||
{
|
||||
void ASEImporter::BuildAnimations(const std::vector<BaseNode *> &nodes) {
|
||||
// check whether we have at least one mesh which has animations
|
||||
std::vector<ASE::BaseNode *>::const_iterator i = nodes.begin();
|
||||
unsigned int iNum = 0;
|
||||
|
@ -370,8 +369,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
|||
nd->mNodeName.Set(me->mName);
|
||||
|
||||
// copy position keys
|
||||
if (me->mAnim.akeyPositions.size() > 1 )
|
||||
{
|
||||
if (me->mAnim.akeyPositions.size() > 1) {
|
||||
// Allocate the key array and fill it
|
||||
nd->mNumPositionKeys = (unsigned int)me->mAnim.akeyPositions.size();
|
||||
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
|
||||
|
@ -424,8 +422,7 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output cameras
|
||||
void ASEImporter::BuildCameras()
|
||||
{
|
||||
void ASEImporter::BuildCameras() {
|
||||
if (!mParser->m_vCameras.empty()) {
|
||||
pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
|
||||
pcScene->mCameras = new aiCamera *[pcScene->mNumCameras];
|
||||
|
@ -446,8 +443,7 @@ void ASEImporter::BuildCameras()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output lights
|
||||
void ASEImporter::BuildLights()
|
||||
{
|
||||
void ASEImporter::BuildLights() {
|
||||
if (!mParser->m_vLights.empty()) {
|
||||
pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
|
||||
pcScene->mLights = new aiLight *[pcScene->mNumLights];
|
||||
|
@ -462,8 +458,7 @@ void ASEImporter::BuildLights()
|
|||
out->mDirection = aiVector3D(0.f, 0.f, -1.f);
|
||||
|
||||
out->mName.Set(in.mName);
|
||||
switch (in.mLightType)
|
||||
{
|
||||
switch (in.mLightType) {
|
||||
case ASE::Light::TARGET:
|
||||
out->mType = aiLightSource_SPOT;
|
||||
out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
|
||||
|
@ -486,16 +481,14 @@ void ASEImporter::BuildLights()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode* pcParent,const char* szName)
|
||||
{
|
||||
aiNode *pcParent, const char *szName) {
|
||||
aiMatrix4x4 m;
|
||||
AddNodes(nodes, pcParent, szName, m);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Add meshes to a given node
|
||||
void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
|
||||
{
|
||||
void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
|
||||
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
|
||||
// Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
|
||||
const aiMesh *pcMesh = pcScene->mMeshes[i];
|
||||
|
@ -549,8 +542,7 @@ void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
|
|||
// Add child nodes to a given parent node
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode *pcParent, const char *szName,
|
||||
const aiMatrix4x4& mat)
|
||||
{
|
||||
const aiMatrix4x4 &mat) {
|
||||
const size_t len = szName ? ::strlen(szName) : 0;
|
||||
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
|
||||
|
||||
|
@ -564,8 +556,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
if (szName) {
|
||||
if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str()))
|
||||
continue;
|
||||
}
|
||||
else if (snode->mParent.length())
|
||||
} else if (snode->mParent.length())
|
||||
continue;
|
||||
|
||||
(*it)->mProcessed = true;
|
||||
|
@ -595,8 +586,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
// slightly inconvinient here and a better solution should
|
||||
// be used when this code is refactored next.
|
||||
AddMeshes(snode, node);
|
||||
}
|
||||
else if (is_not_qnan( snode->mTargetPosition.x )) {
|
||||
} else if (is_not_qnan(snode->mTargetPosition.x)) {
|
||||
// If this is a target camera or light we generate a small
|
||||
// child node which marks the position of the camera
|
||||
// target (the direction information is contained in *this*
|
||||
|
@ -624,7 +614,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
node->mNumChildren++;
|
||||
|
||||
// What we did is so great, it is at least worth a debug message
|
||||
ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ASE: Generating separate target node (" + snode->mName + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,7 +634,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Build the output node graph
|
||||
void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
|
||||
ai_assert(NULL != pcScene);
|
||||
ai_assert(nullptr != pcScene);
|
||||
|
||||
// allocate the one and only root node
|
||||
aiNode *root = pcScene->mRootNode = new aiNode();
|
||||
|
@ -663,7 +653,7 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
|
|||
}
|
||||
|
||||
// add all nodes
|
||||
AddNodes(nodes,ch,NULL);
|
||||
AddNodes(nodes, ch, nullptr);
|
||||
|
||||
// now iterate through al nodes and find those that have not yet
|
||||
// been added to the nodegraph (= their parent could not be recognized)
|
||||
|
@ -723,9 +713,9 @@ void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
|
|||
pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
|
||||
}
|
||||
|
||||
// Reset the third color set to NULL - we used this field to store a temporary pointer
|
||||
// Reset the third color set to nullptr - we used this field to store a temporary pointer
|
||||
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i)
|
||||
pcScene->mMeshes[i]->mColors[2] = NULL;
|
||||
pcScene->mMeshes[i]->mColors[2] = nullptr;
|
||||
|
||||
// The root node should not have at least one child or the file is valid
|
||||
if (!pcScene->mRootNode->mNumChildren) {
|
||||
|
@ -773,8 +763,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
|
|||
// iterate through all faces in the mesh
|
||||
unsigned int iCurrent = 0, fi = 0;
|
||||
for (std::vector<ASE::Face>::iterator i = mesh.mFaces.begin(); i != mesh.mFaces.end(); ++i, ++fi) {
|
||||
for (unsigned int n = 0; n < 3;++n,++iCurrent)
|
||||
{
|
||||
for (unsigned int n = 0; n < 3; ++n, ++iCurrent) {
|
||||
mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
|
||||
|
||||
// add texture coordinates
|
||||
|
@ -814,8 +803,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Copy a texture from the ASE structs to the output material
|
||||
void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
|
||||
{
|
||||
void CopyASETexture(aiMaterial &mat, ASE::Texture &texture, aiTextureType type) {
|
||||
// Setup the texture name
|
||||
aiString tex;
|
||||
tex.Set(texture.mMapName);
|
||||
|
@ -831,8 +819,7 @@ void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert from ASE material to output material
|
||||
void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
||||
{
|
||||
void ASEImporter::ConvertMaterial(ASE::Material &mat) {
|
||||
// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
|
||||
|
||||
// Allocate the output material
|
||||
|
@ -855,16 +842,14 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
mat.pcInstance->AddProperty(&mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
|
||||
// shininess
|
||||
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
|
||||
{
|
||||
if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength) {
|
||||
mat.pcInstance->AddProperty(&mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
|
||||
mat.pcInstance->AddProperty(&mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
}
|
||||
// If there is no shininess, we can disable phong lighting
|
||||
else if (D3DS::Discreet3DS::Metal == mat.mShading ||
|
||||
D3DS::Discreet3DS::Phong == mat.mShading ||
|
||||
D3DS::Discreet3DS::Blinn == mat.mShading)
|
||||
{
|
||||
D3DS::Discreet3DS::Blinn == mat.mShading) {
|
||||
mat.mShading = D3DS::Discreet3DS::Gouraud;
|
||||
}
|
||||
|
||||
|
@ -872,35 +857,37 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
mat.pcInstance->AddProperty<ai_real>(&mat.mTransparency, 1, AI_MATKEY_OPACITY);
|
||||
|
||||
// Two sided rendering?
|
||||
if (mat.mTwoSided)
|
||||
{
|
||||
if (mat.mTwoSided) {
|
||||
int i = 1;
|
||||
mat.pcInstance->AddProperty<int>(&i, 1, AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
// shading mode
|
||||
aiShadingMode eShading = aiShadingMode_NoShading;
|
||||
switch (mat.mShading)
|
||||
{
|
||||
switch (mat.mShading) {
|
||||
case D3DS::Discreet3DS::Flat:
|
||||
eShading = aiShadingMode_Flat; break;
|
||||
eShading = aiShadingMode_Flat;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Phong:
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
eShading = aiShadingMode_Phong;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Blinn:
|
||||
eShading = aiShadingMode_Blinn; break;
|
||||
eShading = aiShadingMode_Blinn;
|
||||
break;
|
||||
|
||||
// I don't know what "Wire" shading should be,
|
||||
// assume it is simple lambertian diffuse (L dot N) shading
|
||||
case D3DS::Discreet3DS::Wire:
|
||||
{
|
||||
case D3DS::Discreet3DS::Wire: {
|
||||
// set the wireframe flag
|
||||
unsigned int iWire = 1;
|
||||
mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
case D3DS::Discreet3DS::Gouraud:
|
||||
eShading = aiShadingMode_Gouraud; break;
|
||||
eShading = aiShadingMode_Gouraud;
|
||||
break;
|
||||
case D3DS::Discreet3DS::Metal:
|
||||
eShading = aiShadingMode_CookTorrance; break;
|
||||
eShading = aiShadingMode_CookTorrance;
|
||||
break;
|
||||
}
|
||||
mat.pcInstance->AddProperty<int>((int *)&eShading, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
|
@ -934,7 +921,8 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
|
||||
// store the name of the material itself, too
|
||||
if (mat.mName.length() > 0) {
|
||||
aiString tex;tex.Set( mat.mName);
|
||||
aiString tex;
|
||||
tex.Set(mat.mName);
|
||||
mat.pcInstance->AddProperty(&tex, AI_MATKEY_NAME);
|
||||
}
|
||||
return;
|
||||
|
@ -942,8 +930,7 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build output meshes
|
||||
void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
|
||||
{
|
||||
void ASEImporter::ConvertMeshes(ASE::Mesh &mesh, std::vector<aiMesh *> &avOutMeshes) {
|
||||
// validate the material index of the mesh
|
||||
if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
|
||||
mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size() - 1;
|
||||
|
@ -952,8 +939,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// If the material the mesh is assigned to is consisting of submeshes, split it
|
||||
if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
|
||||
std::vector<ASE::Material> vSubMaterials = mParser->
|
||||
m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
|
||||
std::vector<ASE::Material> vSubMaterials = mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
|
||||
|
||||
std::vector<unsigned int> *aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
|
||||
|
||||
|
@ -965,8 +951,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// use the last material instead
|
||||
aiSplit[vSubMaterials.size() - 1].push_back(i);
|
||||
}
|
||||
else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
|
||||
} else
|
||||
aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
|
||||
}
|
||||
|
||||
// now generate submeshes
|
||||
|
@ -994,7 +980,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
|
||||
|
||||
// receive output vertex weights
|
||||
std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
|
||||
std::vector<std::pair<unsigned int, float>> *avOutputBones = nullptr;
|
||||
if (!mesh.mBones.empty()) {
|
||||
avOutputBones = new std::vector<std::pair<unsigned int, float>>[mesh.mBones.size()];
|
||||
}
|
||||
|
@ -1041,8 +1027,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
}
|
||||
// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
|
||||
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
|
||||
if (!mesh.amTexCoords[c].empty())
|
||||
{
|
||||
if (!mesh.amTexCoords[c].empty()) {
|
||||
p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
|
||||
iBase = 0;
|
||||
for (unsigned int q = 0; q < aiSplit[p].size(); ++q) {
|
||||
|
@ -1075,8 +1060,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
p_pcOut->mBones = new aiBone *[p_pcOut->mNumBones];
|
||||
aiBone **pcBone = p_pcOut->mBones;
|
||||
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
|
||||
{
|
||||
for (unsigned int mrspock = 0; mrspock < mesh.mBones.size(); ++mrspock) {
|
||||
if (!avOutputBones[mrspock].empty()) {
|
||||
// we will need this bone. add it to the output mesh and
|
||||
// add all per-vertex weights
|
||||
|
@ -1086,8 +1070,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
|
||||
pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
||||
|
||||
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
|
||||
{
|
||||
for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights; ++captainkirk) {
|
||||
const std::pair<unsigned int, float> &ref = avOutputBones[mrspock][captainkirk];
|
||||
pc->mWeights[captainkirk].mVertexId = ref.first;
|
||||
pc->mWeights[captainkirk].mWeight = ref.second;
|
||||
|
@ -1102,9 +1085,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
}
|
||||
// delete storage
|
||||
delete[] aiSplit;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Otherwise we can simply copy the data to one output mesh
|
||||
// This codepath needs less memory and uses fast memcpy()s
|
||||
// to do the actual copying. So I think it is worth the
|
||||
|
@ -1189,8 +1170,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
for (std::vector<std::pair<int, float>>::const_iterator
|
||||
ronaldweasley = (*harrypotter).mBoneWeights.begin();
|
||||
ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
|
||||
{
|
||||
ronaldweasley != (*harrypotter).mBoneWeights.end(); ++ronaldweasley) {
|
||||
aiVertexWeight weight;
|
||||
weight.mVertexId = quak;
|
||||
weight.mWeight = (*ronaldweasley).second;
|
||||
|
@ -1222,21 +1202,18 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup proper material indices and build output materials
|
||||
void ASEImporter::BuildMaterialIndices()
|
||||
{
|
||||
ai_assert(NULL != pcScene);
|
||||
void ASEImporter::BuildMaterialIndices() {
|
||||
ai_assert(nullptr != pcScene);
|
||||
|
||||
// iterate through all materials and check whether we need them
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
|
||||
{
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
|
||||
ASE::Material &mat = mParser->m_vMaterials[iMat];
|
||||
if (mat.bNeed) {
|
||||
// Convert it to the aiMaterial layout
|
||||
ConvertMaterial(mat);
|
||||
++pcScene->mNumMaterials;
|
||||
}
|
||||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
|
||||
{
|
||||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
|
||||
ASE::Material &submat = mat.avSubMaterials[iSubMat];
|
||||
if (submat.bNeed) {
|
||||
// Convert it to the aiMaterial layout
|
||||
|
@ -1253,9 +1230,8 @@ void ASEImporter::BuildMaterialIndices()
|
|||
unsigned int iNum = 0;
|
||||
for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size(); ++iMat) {
|
||||
ASE::Material &mat = mParser->m_vMaterials[iMat];
|
||||
if (mat.bNeed)
|
||||
{
|
||||
ai_assert(NULL != mat.pcInstance);
|
||||
if (mat.bNeed) {
|
||||
ai_assert(nullptr != mat.pcInstance);
|
||||
pcScene->mMaterials[iNum] = mat.pcInstance;
|
||||
|
||||
// Store the internal material, too
|
||||
|
@ -1263,14 +1239,12 @@ void ASEImporter::BuildMaterialIndices()
|
|||
|
||||
// Iterate through all meshes and search for one which is using
|
||||
// this top-level material index
|
||||
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
|
||||
{
|
||||
for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes; ++iMesh) {
|
||||
aiMesh *mesh = pcScene->mMeshes[iMesh];
|
||||
if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
|
||||
iMat == (uintptr_t)mesh->mColors[3])
|
||||
{
|
||||
iMat == (uintptr_t)mesh->mColors[3]) {
|
||||
mesh->mMaterialIndex = iNum;
|
||||
mesh->mColors[3] = NULL;
|
||||
mesh->mColors[3] = nullptr;
|
||||
}
|
||||
}
|
||||
iNum++;
|
||||
|
@ -1278,7 +1252,7 @@ void ASEImporter::BuildMaterialIndices()
|
|||
for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size(); ++iSubMat) {
|
||||
ASE::Material &submat = mat.avSubMaterials[iSubMat];
|
||||
if (submat.bNeed) {
|
||||
ai_assert(NULL != submat.pcInstance);
|
||||
ai_assert(nullptr != submat.pcInstance);
|
||||
pcScene->mMaterials[iNum] = submat.pcInstance;
|
||||
|
||||
// Store the internal material, too
|
||||
|
@ -1291,7 +1265,7 @@ void ASEImporter::BuildMaterialIndices()
|
|||
|
||||
if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
|
||||
mesh->mMaterialIndex = iNum;
|
||||
mesh->mColors[3] = NULL;
|
||||
mesh->mColors[3] = nullptr;
|
||||
}
|
||||
}
|
||||
iNum++;
|
||||
|
@ -1307,13 +1281,11 @@ void ASEImporter::BuildMaterialIndices()
|
|||
// Generate normal vectors basing on smoothing groups
|
||||
bool ASEImporter::GenerateNormals(ASE::Mesh &mesh) {
|
||||
|
||||
if (!mesh.mNormals.empty() && !configRecomputeNormals)
|
||||
{
|
||||
if (!mesh.mNormals.empty() && !configRecomputeNormals) {
|
||||
// Check whether there are only uninitialized normals. If there are
|
||||
// some, skip all normals from the file and compute them on our own
|
||||
for (std::vector<aiVector3D>::const_iterator qq = mesh.mNormals.begin(); qq != mesh.mNormals.end(); ++qq) {
|
||||
if ((*qq).x || (*qq).y || (*qq).z)
|
||||
{
|
||||
if ((*qq).x || (*qq).y || (*qq).z) {
|
||||
return true;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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,7 +56,7 @@ 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 {
|
||||
|
@ -66,16 +65,15 @@ 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
|
||||
}
|
||||
|
||||
|
@ -93,18 +91,15 @@ 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 {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
|
@ -121,10 +116,8 @@ struct Material : public D3DS::Material
|
|||
return *this;
|
||||
}
|
||||
|
||||
|
||||
~Material() {}
|
||||
|
||||
|
||||
//! Contains all sub materials of this material
|
||||
std::vector<Material> avSubMaterials;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -196,12 +189,13 @@ struct Animation {
|
|||
TRACK = 0x0,
|
||||
BEZIER = 0x1,
|
||||
TCB = 0x2
|
||||
} mRotationType, mScalingType, mPositionType;
|
||||
} mRotationType,
|
||||
mScalingType, mPositionType;
|
||||
|
||||
Animation() AI_NO_EXCEPT
|
||||
: mRotationType (TRACK)
|
||||
, mScalingType (TRACK)
|
||||
, mPositionType (TRACK) {
|
||||
: mRotationType(TRACK),
|
||||
mScalingType(TRACK),
|
||||
mPositionType(TRACK) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -246,10 +240,8 @@ struct BaseNode {
|
|||
} 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,13 +281,8 @@ 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) {
|
||||
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;
|
||||
};
|
||||
|
@ -414,7 +391,6 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//! Construct a parser from a given input file which is
|
||||
//! guaranteed to be terminated with zero.
|
||||
|
@ -428,9 +404,7 @@ public:
|
|||
//! Parses the file into the parsers internal representation
|
||||
void Parse();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//! Parse the *SCENE block in a file
|
||||
void ParseLV1SceneBlock();
|
||||
|
@ -646,7 +620,6 @@ private:
|
|||
bool ParseString(std::string &out, const char *szName);
|
||||
|
||||
public:
|
||||
|
||||
//! Pointer to current data
|
||||
const char *filePtr;
|
||||
|
||||
|
@ -695,9 +668,8 @@ public:
|
|||
unsigned int iFileFormat;
|
||||
};
|
||||
|
||||
|
||||
} // Namespace ASE
|
||||
} // Namespace ASSIMP
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
|
|
@ -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,
|
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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());
|
|
@ -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,
|
|
@ -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>
|
||||
|
@ -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) {
|
|
@ -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)
|
|
@ -9,16 +9,17 @@ 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
|
||||
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -156,8 +155,7 @@ public:
|
|||
void Delimit() {
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buff << ' ';
|
||||
first = false;
|
||||
}
|
||||
|
@ -468,8 +466,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
@ -486,19 +483,15 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
|||
}
|
||||
break;
|
||||
|
||||
case aiPTI_String:
|
||||
{
|
||||
case aiPTI_String: {
|
||||
aiString s;
|
||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||
out.SimpleValue(s);
|
||||
}
|
||||
break;
|
||||
case aiPTI_Buffer:
|
||||
{
|
||||
} break;
|
||||
case aiPTI_Buffer: {
|
||||
// binary data is written as series of hex-encoded octets
|
||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
@ -525,8 +518,7 @@ 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);
|
||||
|
@ -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) {
|
||||
|
@ -774,11 +765,10 @@ void Write(JSONWriter& out, const aiScene& ai) {
|
|||
out.EndObj();
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -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
|
|
@ -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("<");
|
||||
break;
|
||||
case '>':
|
||||
out.Append(">");
|
||||
break;
|
||||
case '&':
|
||||
out.Append("&");
|
||||
break;
|
||||
case '\"':
|
||||
out.Append(""");
|
||||
break;
|
||||
case '\'':
|
||||
out.Append("'");
|
||||
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("&"); break;
|
||||
case '\"': buffer.append("""); break;
|
||||
case '\'': buffer.append("'"); break;
|
||||
case '<': buffer.append("<"); break;
|
||||
case '>': buffer.append(">"); 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
|
|
@ -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
|
|
@ -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,22 +73,19 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BVHLoader::BVHLoader()
|
||||
: mLine(),
|
||||
BVHLoader::BVHLoader() :
|
||||
mLine(),
|
||||
mAnimTickDuration(),
|
||||
mAnimNumFrames(),
|
||||
noSkeletonMesh()
|
||||
{}
|
||||
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);
|
||||
|
||||
|
@ -104,22 +100,19 @@ bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
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
|
||||
|
@ -152,8 +145,7 @@ void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSys
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the file
|
||||
void BVHLoader::ReadStructure( aiScene* pScene)
|
||||
{
|
||||
void BVHLoader::ReadStructure(aiScene *pScene) {
|
||||
// first comes hierarchy
|
||||
std::string header = GetNextToken();
|
||||
if (header != "HIERARCHY")
|
||||
|
@ -169,8 +161,7 @@ void BVHLoader::ReadStructure( aiScene* 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\".");
|
||||
|
@ -181,8 +172,7 @@ 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 == "{")
|
||||
|
@ -203,8 +193,7 @@ aiNode* BVHLoader::ReadNode()
|
|||
|
||||
// now read the node's contents
|
||||
std::string siteToken;
|
||||
while( 1)
|
||||
{
|
||||
while (1) {
|
||||
std::string token = GetNextToken();
|
||||
|
||||
// node offset to parent node
|
||||
|
@ -212,15 +201,12 @@ aiNode* BVHLoader::ReadNode()
|
|||
ReadNodeOffset(node);
|
||||
else if (token == "CHANNELS")
|
||||
ReadNodeChannels(internNode);
|
||||
else if( token == "JOINT")
|
||||
{
|
||||
else if (token == "JOINT") {
|
||||
// child node follows
|
||||
aiNode *child = ReadNode();
|
||||
child->mParent = node;
|
||||
childNodes.push_back(child);
|
||||
}
|
||||
else if( token == "End")
|
||||
{
|
||||
} else if (token == "End") {
|
||||
// The real symbol is "End Site". Second part comes in a separate token
|
||||
siteToken.clear();
|
||||
siteToken = GetNextToken();
|
||||
|
@ -230,21 +216,17 @@ aiNode* BVHLoader::ReadNode()
|
|||
aiNode *child = ReadEndSite(nodeName);
|
||||
child->mParent = node;
|
||||
childNodes.push_back(child);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
} 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 << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -256,8 +238,7 @@ 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 != "{")
|
||||
|
@ -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();
|
||||
|
@ -306,14 +286,12 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
for( unsigned int a = 0; a < numChannels; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numChannels; a++) {
|
||||
std::string channelToken = GetNextToken();
|
||||
|
||||
if (channelToken == "Xposition")
|
||||
|
@ -335,8 +313,7 @@ void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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:")
|
||||
|
@ -358,11 +335,9 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
|||
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());
|
||||
|
@ -374,11 +349,9 @@ 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())
|
||||
{
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (!isspace(*mReader))
|
||||
break;
|
||||
|
||||
|
@ -391,8 +364,7 @@ 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())
|
||||
{
|
||||
while (mReader != mBuffer.end()) {
|
||||
if (isspace(*mReader))
|
||||
break;
|
||||
|
||||
|
@ -410,8 +382,7 @@ 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");
|
||||
|
@ -429,15 +400,13 @@ float BVHLoader::GetNextTokenAsFloat()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aborts the file reading with an exception
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& 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];
|
||||
|
@ -453,12 +422,11 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
|
||||
anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
|
||||
|
||||
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
|
||||
// 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] = NULL;
|
||||
anim->mChannels[i] = nullptr;
|
||||
|
||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||
{
|
||||
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;
|
||||
|
@ -467,24 +435,20 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
std::map<BVHLoader::ChannelType, int> channelMap;
|
||||
|
||||
//Build map of channels
|
||||
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
|
||||
{
|
||||
for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
|
||||
channelMap[node.mChannels[channel]] = channel;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -506,13 +470,11 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
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);
|
||||
nodeAnim->mNumPositionKeys = 1;
|
||||
|
@ -528,39 +490,33 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
|
|||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||
aiQuatKey *rotkey = nodeAnim->mRotationKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp);
|
||||
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;
|
|
@ -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,21 +75,19 @@ class BVHLoader : public BaseImporter
|
|||
};
|
||||
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -105,8 +100,6 @@ public:
|
|||
const aiImporterDesc *GetInfo() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
|
@ -42,22 +42,20 @@ 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()
|
||||
{
|
||||
namespace Assimp {
|
||||
template <>
|
||||
const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
|
||||
static auto prefix = "BLEND_BMESH: ";
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
|
@ -66,32 +64,28 @@ using namespace Assimp::Formatter;
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
|
||||
BMesh(mesh),
|
||||
triMesh( NULL )
|
||||
{
|
||||
triMesh(nullptr) {
|
||||
ai_assert(nullptr != mesh);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter( )
|
||||
{
|
||||
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( )
|
||||
{
|
||||
const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
|
||||
AssertValidMesh();
|
||||
AssertValidSizes();
|
||||
PrepareTriMesh();
|
||||
|
||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
||||
{
|
||||
for (int i = 0; i < BMesh->totpoly; ++i) {
|
||||
const MPoly &poly = BMesh->mpoly[i];
|
||||
ConvertPolyToFaces(poly);
|
||||
}
|
||||
|
@ -100,32 +94,25 @@ const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidMesh( )
|
||||
{
|
||||
if ( !ContainsBMesh( ) )
|
||||
{
|
||||
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( ) ) )
|
||||
{
|
||||
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( ) ) )
|
||||
{
|
||||
if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
|
||||
ThrowException("BMesh loop array has incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::PrepareTriMesh( )
|
||||
{
|
||||
if ( triMesh )
|
||||
{
|
||||
void BlenderBMeshConverter::PrepareTriMesh() {
|
||||
if (triMesh) {
|
||||
DestroyTriMesh();
|
||||
}
|
||||
|
||||
|
@ -135,34 +122,27 @@ void BlenderBMeshConverter::PrepareTriMesh( )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::DestroyTriMesh( )
|
||||
{
|
||||
void BlenderBMeshConverter::DestroyTriMesh() {
|
||||
delete triMesh;
|
||||
triMesh = NULL;
|
||||
triMesh = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
||||
{
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
|
||||
const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
|
||||
|
||||
if ( poly.totloop == 3 || poly.totloop == 4 )
|
||||
{
|
||||
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() ) )
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
@ -174,13 +154,13 @@ void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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);
|
||||
|
@ -188,15 +168,13 @@ void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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);
|
||||
|
||||
if ( uv4 )
|
||||
{
|
||||
if (uv4) {
|
||||
memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -45,12 +45,11 @@ 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;
|
||||
|
@ -72,8 +71,7 @@ struct Type {
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNAParser::Parse ()
|
||||
{
|
||||
void DNAParser::Parse() {
|
||||
StreamReaderAny &stream = *db.reader.get();
|
||||
DNA &dna = db.dna;
|
||||
|
||||
|
@ -94,7 +92,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// type dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TYPE")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||
}
|
||||
|
@ -107,7 +106,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// type length dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "TLEN")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||
}
|
||||
|
@ -117,7 +117,8 @@ void DNAParser::Parse ()
|
|||
}
|
||||
|
||||
// structures dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
|
||||
;
|
||||
if (!match4(stream, "STRC")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||
}
|
||||
|
@ -131,8 +132,7 @@ void DNAParser::Parse ()
|
|||
if (n >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure name", n,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
" (there are only ", types.size(), " entries)"));
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
|
@ -153,8 +153,7 @@ void DNAParser::Parse ()
|
|||
if (j >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure field ", j,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
" (there are only ", types.size(), " entries)"));
|
||||
}
|
||||
s.fields.push_back(Field());
|
||||
Field &f = s.fields.back();
|
||||
|
@ -167,8 +166,7 @@ void DNAParser::Parse ()
|
|||
if (j >= names.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid name index in structure field ", j,
|
||||
" (there are only ", names.size(), " entries)"
|
||||
));
|
||||
" (there are only ", names.size(), " entries)"));
|
||||
}
|
||||
|
||||
f.name = names[j];
|
||||
|
@ -192,8 +190,7 @@ void DNAParser::Parse ()
|
|||
if (rb == std::string::npos) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Encountered invalid array declaration ",
|
||||
f.name
|
||||
));
|
||||
f.name));
|
||||
}
|
||||
|
||||
f.flags |= FieldFlag_Array;
|
||||
|
@ -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,8 +230,10 @@ 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) {
|
||||
f << s.name << " " << s.size << "\n\n";
|
||||
|
@ -254,9 +251,7 @@ void DNA :: DumpToFile()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void DNA ::ExtractArraySize(
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]
|
||||
)
|
||||
{
|
||||
size_t array_sizes[2]) {
|
||||
array_sizes[0] = array_sizes[1] = 1;
|
||||
std::string::size_type pos = out.find('[');
|
||||
if (pos++ == std::string::npos) {
|
||||
|
@ -274,9 +269,7 @@ void DNA :: DumpToFile()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const
|
||||
{
|
||||
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>();
|
||||
|
@ -292,16 +285,14 @@ std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
|
|||
DNA::FactoryPair DNA ::GetBlobToStructureConverter(
|
||||
const Structure &structure,
|
||||
const FileDatabase & /*db*/
|
||||
) const
|
||||
{
|
||||
) 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
|
||||
|
@ -320,19 +311,16 @@ void DNA :: AddPrimitiveStructures()
|
|||
structures.back().name = "short";
|
||||
structures.back().size = 2;
|
||||
|
||||
|
||||
indices["char"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "char";
|
||||
structures.back().size = 1;
|
||||
|
||||
|
||||
indices["float"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "float";
|
||||
structures.back().size = 4;
|
||||
|
||||
|
||||
indices["double"] = structures.size();
|
||||
structures.push_back(Structure());
|
||||
structures.back().name = "double";
|
||||
|
@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SectionParser :: Next()
|
||||
{
|
||||
void SectionParser ::Next() {
|
||||
stream.SetCurrentPos(current.start + current.size);
|
||||
|
||||
const char tmp[] = {
|
||||
|
@ -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
|
|
@ -49,10 +49,10 @@ 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
|
||||
|
@ -63,7 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
template <bool,bool> class StreamReader;
|
||||
template <bool, bool>
|
||||
class StreamReader;
|
||||
typedef StreamReader<true, true> StreamReaderAny;
|
||||
|
||||
namespace Blender {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -212,16 +212,15 @@ 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;
|
||||
|
@ -229,11 +228,9 @@ public:
|
|||
|
||||
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. */
|
||||
* 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;
|
||||
|
||||
|
@ -251,8 +248,6 @@ public:
|
|||
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,7 +255,8 @@ 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
|
||||
|
@ -269,9 +265,8 @@ public:
|
|||
|
||||
// --------------------------------------------------------
|
||||
// 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
|
||||
|
@ -332,7 +327,6 @@ public:
|
|||
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,
|
||||
|
@ -354,17 +348,18 @@ private:
|
|||
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,18 +383,18 @@ 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>") {
|
||||
|
@ -410,7 +405,8 @@ 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 * = "") {
|
||||
|
@ -421,13 +417,12 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
|
|||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
|
||||
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;
|
||||
|
||||
bool) const;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Represents the full data structure information for a single BLEND file.
|
||||
|
@ -435,14 +430,11 @@ 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;
|
||||
const FileDatabase &) const;
|
||||
|
||||
typedef std::shared_ptr<ElemBase> (
|
||||
Structure::*AllocProcPtr)() const;
|
||||
|
@ -450,15 +442,13 @@ public:
|
|||
typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
|
||||
|
||||
public:
|
||||
|
||||
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;
|
||||
|
@ -468,7 +458,6 @@ public:
|
|||
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
|
||||
|
@ -493,8 +481,7 @@ public:
|
|||
* @return A null pointer if no appropriate converter is available.*/
|
||||
std::shared_ptr<ElemBase> ConvertBlobToStructure(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
const FileDatabase &db) const;
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Find a suitable conversion function for a given Structure.
|
||||
|
@ -506,9 +493,7 @@ public:
|
|||
* @return A null pointer in .first if no appropriate converter is available.*/
|
||||
FactoryPair GetBlobToStructureConverter(
|
||||
const Structure &structure,
|
||||
const FileDatabase& db
|
||||
) const;
|
||||
|
||||
const FileDatabase &db) const;
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
// --------------------------------------------------------
|
||||
|
@ -528,24 +513,28 @@ public:
|
|||
* encountered. */
|
||||
static void ExtractArraySize(
|
||||
const std::string &out,
|
||||
size_t array_sizes[2]
|
||||
);
|
||||
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,8 +550,6 @@ 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 {
|
||||
return address.val < o.address.val;
|
||||
|
@ -582,45 +569,36 @@ inline bool operator< (const Pointer& a, const Pointer& b) {
|
|||
// -------------------------------------------------------------------------------
|
||||
/** 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 {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------
|
||||
/** Advance to the next section.
|
||||
* @throw DeadlyImportError if the last chunk was passed. */
|
||||
void Next();
|
||||
|
||||
public:
|
||||
|
||||
FileBlockHead current;
|
||||
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 ()
|
||||
Statistics() :
|
||||
fields_read(), pointers_resolved(), cache_hits()
|
||||
// , blocks_read ()
|
||||
, cached_objects ()
|
||||
{}
|
||||
,
|
||||
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;
|
||||
|
||||
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,14 +650,14 @@ 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 (
|
||||
template <typename T>
|
||||
void get(
|
||||
const Structure &s,
|
||||
TOUT<T> &out,
|
||||
const Pointer &ptr) const;
|
||||
|
@ -700,27 +670,27 @@ 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,
|
||||
template <typename T>
|
||||
void set(const Structure &s,
|
||||
const TOUT<T> &out,
|
||||
const Pointer &ptr);
|
||||
|
||||
private:
|
||||
|
||||
mutable vector<StructureCache> caches;
|
||||
const FileDatabase &db;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
template <> class ObjectCache<Blender::vector>
|
||||
{
|
||||
template <>
|
||||
class ObjectCache<Blender::vector> {
|
||||
public:
|
||||
|
||||
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
|
||||
|
@ -731,16 +701,13 @@ public:
|
|||
/** 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
|
||||
|
@ -752,7 +719,6 @@ public:
|
|||
vector<FileBlockHead> entries;
|
||||
|
||||
public:
|
||||
|
||||
Statistics &stats() const {
|
||||
return _stats;
|
||||
}
|
||||
|
@ -772,8 +738,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
|
||||
mutable Statistics _stats;
|
||||
#endif
|
||||
|
@ -791,18 +755,14 @@ private:
|
|||
// -------------------------------------------------------------------------------
|
||||
/** 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
|
||||
|
@ -814,14 +774,12 @@ public:
|
|||
void Parse();
|
||||
|
||||
public:
|
||||
|
||||
/** Obtain a reference to the extracted DNA information */
|
||||
const Blender::DNA &GetDNA() const {
|
||||
return db.dna;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
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"
|
||||
|
|
@ -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];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
|
@ -45,27 +45,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the Blender3D importer class.
|
||||
*/
|
||||
|
||||
|
||||
//#define ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||
// Uncomment this to disable support for (gzip)compressed .BLEND files
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
|
||||
#include "BlenderIntermediate.h"
|
||||
#include "BlenderModifier.h"
|
||||
#include "BlenderBMesh.h"
|
||||
#include "BlenderCustomData.h"
|
||||
#include "BlenderIntermediate.h"
|
||||
#include "BlenderModifier.h"
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/MemoryIOWrapper.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
|
||||
// zlib is needed for compressed blend files
|
||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
||||
|
@ -76,12 +74,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
template<> const char* LogFunctions<BlenderImporter>::Prefix()
|
||||
{
|
||||
template <>
|
||||
const char *LogFunctions<BlenderImporter>::Prefix() {
|
||||
static auto prefix = "BLEND: ";
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Blender;
|
||||
|
@ -100,18 +98,16 @@ static const aiImporterDesc blenderDesc = {
|
|||
"blend"
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BlenderImporter::BlenderImporter()
|
||||
: modifier_cache(new BlenderModifierShowcase()) {
|
||||
BlenderImporter::BlenderImporter() :
|
||||
modifier_cache(new BlenderModifierShowcase()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BlenderImporter::~BlenderImporter()
|
||||
{
|
||||
BlenderImporter::~BlenderImporter() {
|
||||
delete modifier_cache;
|
||||
}
|
||||
|
||||
|
@ -120,8 +116,7 @@ static const char* TokensForSearch[] = { "blender" };
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == "blend") {
|
||||
return true;
|
||||
|
@ -136,36 +131,30 @@ bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, b
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// List all extensions handled by this loader
|
||||
void BlenderImporter::GetExtensionList(std::set<std::string>& app)
|
||||
{
|
||||
void BlenderImporter::GetExtensionList(std::set<std::string> &app) {
|
||||
app.insert("blend");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader registry entry
|
||||
const aiImporterDesc* BlenderImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *BlenderImporter::GetInfo() const {
|
||||
return &blenderDesc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||
// nothing to be done for the moment
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void BlenderImporter::InternReadFile(const std::string &pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
aiScene *pScene, IOSystem *pIOHandler) {
|
||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||
std::vector<Bytef> uncompressed;
|
||||
#endif
|
||||
|
||||
|
||||
FileDatabase file;
|
||||
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||
if (!stream) {
|
||||
|
@ -206,7 +195,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
|||
inflateInit2(&zstream, 16 + MAX_WBITS);
|
||||
|
||||
zstream.next_in = reinterpret_cast<Bytef *>(reader->GetPtr());
|
||||
zstream.avail_in = reader->GetRemainingSize();
|
||||
zstream.avail_in = (uInt)reader->GetRemainingSize();
|
||||
|
||||
size_t total = 0l;
|
||||
|
||||
|
@ -227,8 +216,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
|||
total += have;
|
||||
uncompressed.resize(total);
|
||||
memcpy(uncompressed.data() + total - have, block, have);
|
||||
}
|
||||
while (ret != Z_STREAM_END);
|
||||
} while (ret != Z_STREAM_END);
|
||||
|
||||
// terminate zlib
|
||||
inflateEnd(&zstream);
|
||||
|
@ -252,8 +240,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
LogInfo((format(), "Blender version is ", magic[0], ".", magic + 1,
|
||||
" (64bit: ", file.i64bit ? "true" : "false",
|
||||
", little endian: ",file.little?"true":"false",")"
|
||||
));
|
||||
", little endian: ", file.little ? "true" : "false", ")"));
|
||||
|
||||
ParseBlendFile(file, stream);
|
||||
|
||||
|
@ -264,14 +251,14 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream> stream)
|
||||
{
|
||||
void BlenderImporter::ParseBlendFile(FileDatabase &out, std::shared_ptr<IOStream> stream) {
|
||||
out.reader = std::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream, out.little));
|
||||
|
||||
DNAParser dna_reader(out);
|
||||
const DNA* dna = NULL;
|
||||
const DNA *dna = nullptr;
|
||||
|
||||
out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks
|
||||
out.entries.reserve(128);
|
||||
{ // even small BLEND files tend to consist of many file blocks
|
||||
SectionParser parser(*out.reader.get(), out.i64bit);
|
||||
|
||||
// first parse the file in search for the DNA and insert all other sections into the database
|
||||
|
@ -280,8 +267,7 @@ void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream
|
|||
|
||||
if (head.id == "ENDB") {
|
||||
break; // only valid end of the file
|
||||
}
|
||||
else if (head.id == "DNA1") {
|
||||
} else if (head.id == "DNA1") {
|
||||
dna_reader.Parse();
|
||||
dna = &dna_reader.GetDNA();
|
||||
continue;
|
||||
|
@ -298,9 +284,8 @@ void BlenderImporter::ParseBlendFile(FileDatabase& out, std::shared_ptr<IOStream
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
|
||||
{
|
||||
const FileBlockHead* block = NULL;
|
||||
void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
|
||||
const FileBlockHead *block = nullptr;
|
||||
std::map<std::string, size_t>::const_iterator it = file.dna.indices.find("Scene");
|
||||
if (it == file.dna.indices.end()) {
|
||||
ThrowException("There is no `Scene` structure record");
|
||||
|
@ -332,14 +317,12 @@ void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
|
|||
"(Stats) Fields read: ", file.stats().fields_read,
|
||||
", pointers resolved: ", file.stats().pointers_resolved,
|
||||
", cache hits: ", file.stats().cache_hits,
|
||||
", cached objects: " ,file.stats().cached_objects
|
||||
);
|
||||
", cached objects: ", file.stats().cached_objects);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileDatabase& file)
|
||||
{
|
||||
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
|
||||
ConversionData conv(file);
|
||||
|
||||
// FIXME it must be possible to take the hierarchy directly from
|
||||
|
@ -418,9 +401,10 @@ void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileD
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const MTex* tex, const Image* img, ConversionData& conv_data)
|
||||
{
|
||||
(void)mat; (void)tex; (void)conv_data;
|
||||
void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const MTex *tex, const Image *img, ConversionData &conv_data) {
|
||||
(void)mat;
|
||||
(void)tex;
|
||||
(void)conv_data;
|
||||
aiString name;
|
||||
|
||||
// check if the file contents are bundled with the BLEND file
|
||||
|
@ -466,13 +450,11 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
|||
else if (map_type & MTex::MapType_NORM) {
|
||||
if (tex->tex->imaflag & Tex::ImageFlags_NORMALMAP) {
|
||||
texture_type = aiTextureType_NORMALS;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
texture_type = aiTextureType_HEIGHT;
|
||||
}
|
||||
out->AddProperty(&tex->norfac, 1, AI_MATKEY_BUMPSCALING);
|
||||
}
|
||||
else if (map_type & MTex::MapType_COLSPEC)
|
||||
} else if (map_type & MTex::MapType_COLSPEC)
|
||||
texture_type = aiTextureType_SPECULAR;
|
||||
else if (map_type & MTex::MapType_COLMIR)
|
||||
texture_type = aiTextureType_REFLECTION;
|
||||
|
@ -493,26 +475,23 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M
|
|||
|
||||
out->AddProperty(&name, AI_MATKEY_TEXTURE(texture_type,
|
||||
conv_data.next_texture[texture_type]++));
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
|
||||
{
|
||||
(void)mat; (void)tex; (void)conv_data;
|
||||
void BlenderImporter::AddSentinelTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
|
||||
(void)mat;
|
||||
(void)tex;
|
||||
(void)conv_data;
|
||||
|
||||
aiString name;
|
||||
name.length = ai_snprintf(name.data, MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
|
||||
GetTextureTypeDisplayString(tex->tex->type)
|
||||
);
|
||||
GetTextureTypeDisplayString(tex->tex->type));
|
||||
out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(
|
||||
conv_data.next_texture[aiTextureType_DIFFUSE]++)
|
||||
);
|
||||
conv_data.next_texture[aiTextureType_DIFFUSE]++));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
|
||||
{
|
||||
void BlenderImporter::ResolveTexture(aiMaterial *out, const Material *mat, const MTex *tex, ConversionData &conv_data) {
|
||||
const Tex *rtex = tex->tex.get();
|
||||
if (!rtex || !rtex->type) {
|
||||
return;
|
||||
|
@ -521,8 +500,7 @@ void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const
|
|||
// We can't support most of the texture types because they're mostly procedural.
|
||||
// These are substituted by a dummy texture.
|
||||
const char *dispnam = "";
|
||||
switch( rtex->type )
|
||||
{
|
||||
switch (rtex->type) {
|
||||
// these are listed in blender's UI
|
||||
case Tex::Type_CLOUDS:
|
||||
case Tex::Type_WOOD:
|
||||
|
@ -559,8 +537,7 @@ void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData& conv_data)
|
||||
{
|
||||
void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData &conv_data) {
|
||||
// add a default material if necessary
|
||||
unsigned int index = static_cast<unsigned int>(-1);
|
||||
for (aiMesh *mesh : conv_data.meshes.get()) {
|
||||
|
@ -593,8 +570,7 @@ void BlenderImporter::BuildDefaultMaterial(Blender::ConversionData& conv_data)
|
|||
}
|
||||
}
|
||||
|
||||
void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
|
||||
{
|
||||
void BlenderImporter::AddBlendParams(aiMaterial *result, const Material *source) {
|
||||
aiColor3D diffuseColor(source->r, source->g, source->b);
|
||||
result->AddProperty(&diffuseColor, 1, "$mat.blend.diffuse.color", 0, 0);
|
||||
|
||||
|
@ -607,7 +583,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
|
|||
int diffuseRamp = 0;
|
||||
result->AddProperty(&diffuseRamp, 1, "$mat.blend.diffuse.ramp", 0, 0);
|
||||
|
||||
|
||||
aiColor3D specularColor(source->specr, source->specg, source->specb);
|
||||
result->AddProperty(&specularColor, 1, "$mat.blend.specular.color", 0, 0);
|
||||
|
||||
|
@ -623,7 +598,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
|
|||
int specularHardness = source->har;
|
||||
result->AddProperty(&specularHardness, 1, "$mat.blend.specular.hardness", 0, 0);
|
||||
|
||||
|
||||
int transparencyUse = source->mode & MA_TRANSPARENCY ? 1 : 0;
|
||||
result->AddProperty(&transparencyUse, 1, "$mat.blend.transparency.use", 0, 0);
|
||||
|
||||
|
@ -666,7 +640,6 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
|
|||
int transparencyGlossSamples = source->samp_gloss_tra;
|
||||
result->AddProperty(&transparencyGlossSamples, 1, "$mat.blend.transparency.glossSamples", 0, 0);
|
||||
|
||||
|
||||
int mirrorUse = source->mode & MA_RAYMIRROR ? 1 : 0;
|
||||
result->AddProperty(&mirrorUse, 1, "$mat.blend.mirror.use", 0, 0);
|
||||
|
||||
|
@ -704,8 +677,7 @@ void BlenderImporter::AddBlendParams(aiMaterial* result, const Material* source)
|
|||
result->AddProperty(&mirrorGlossAnisotropic, 1, "$mat.blend.mirror.glossAnisotropic", 0, 0);
|
||||
}
|
||||
|
||||
void BlenderImporter::BuildMaterials(ConversionData& conv_data)
|
||||
{
|
||||
void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
|
||||
conv_data.materials->reserve(conv_data.materials_raw.size());
|
||||
|
||||
BuildDefaultMaterial(conv_data);
|
||||
|
@ -773,34 +745,28 @@ void BlenderImporter::BuildMaterials(ConversionData& conv_data)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::CheckActualType(const ElemBase* dt, const char* check)
|
||||
{
|
||||
void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
|
||||
ai_assert(dt);
|
||||
if (strcmp(dt->dna_type, check)) {
|
||||
ThrowException((format(),
|
||||
"Expected object at ", std::hex, dt, " to be of type `", check,
|
||||
"`, but it claims to be a `",dt->dna_type,"`instead"
|
||||
));
|
||||
"`, but it claims to be a `", dt->dna_type, "`instead"));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::NotSupportedObjectType(const Object* obj, const char* type)
|
||||
{
|
||||
void BlenderImporter::NotSupportedObjectType(const Object *obj, const char *type) {
|
||||
LogWarn((format(), "Object `", obj->id.name, "` - type is unsupported: `", type, "`, skipping"));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/, const Mesh *mesh,
|
||||
ConversionData& conv_data, TempArray<std::vector,aiMesh>& temp
|
||||
)
|
||||
{
|
||||
ConversionData &conv_data, TempArray<std::vector, aiMesh> &temp) {
|
||||
// TODO: Resolve various problems with BMesh triangulation before re-enabling.
|
||||
// See issues #400, #373, #318 #315 and #132.
|
||||
#if defined(TODO_FIX_BMESH_CONVERSION)
|
||||
BlenderBMeshConverter BMeshConverter(mesh);
|
||||
if ( BMeshConverter.ContainsBMesh( ) )
|
||||
{
|
||||
if (BMeshConverter.ContainsBMesh()) {
|
||||
mesh = BMeshConverter.TriangulateBMesh();
|
||||
}
|
||||
#endif
|
||||
|
@ -874,18 +840,16 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
std::shared_ptr<Material> mat = mesh->mat[it.first];
|
||||
const std::deque<std::shared_ptr<Material>>::iterator has = std::find(
|
||||
conv_data.materials_raw.begin(),
|
||||
conv_data.materials_raw.end(),mat
|
||||
);
|
||||
conv_data.materials_raw.end(), mat);
|
||||
|
||||
if (has != conv_data.materials_raw.end()) {
|
||||
out->mMaterialIndex = static_cast<unsigned int>(std::distance(conv_data.materials_raw.begin(), has));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out->mMaterialIndex = static_cast<unsigned int>(conv_data.materials_raw.size());
|
||||
conv_data.materials_raw.push_back(mat);
|
||||
}
|
||||
}
|
||||
else out->mMaterialIndex = static_cast<unsigned int>( -1 );
|
||||
} else
|
||||
out->mMaterialIndex = static_cast<unsigned int>(-1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->totface; ++i) {
|
||||
|
@ -966,8 +930,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
++vn;
|
||||
|
||||
out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
}
|
||||
else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
} else
|
||||
out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
|
||||
// }
|
||||
// }
|
||||
|
@ -990,8 +954,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
// which are assigned by the genblenddna.py script and
|
||||
// cannot be changed without breaking the entire
|
||||
// import process.
|
||||
for (int j = 0;j < mf.totloop; ++j)
|
||||
{
|
||||
for (int j = 0; j < mf.totloop; ++j) {
|
||||
const MLoop &loop = mesh->mloop[mf.loopstart + j];
|
||||
|
||||
if (loop.v >= mesh->totvert) {
|
||||
|
@ -1010,14 +973,10 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
|
||||
++vo;
|
||||
++vn;
|
||||
|
||||
}
|
||||
if (mf.totloop == 3)
|
||||
{
|
||||
if (mf.totloop == 3) {
|
||||
out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
}
|
||||
}
|
||||
|
@ -1056,13 +1015,13 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
|
||||
}
|
||||
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
|
||||
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
|
||||
ai_assert(0 != (*it)->mNumVertices);
|
||||
ai_assert(0 != (*it)->mNumFaces);
|
||||
const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
|
||||
if (itMatTexUvMapping == matTexUvMappings.end()) {
|
||||
// default behaviour like before
|
||||
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// create texture coords for every mapped tex
|
||||
for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
|
||||
(*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
|
||||
|
@ -1125,7 +1084,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
|
||||
}
|
||||
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
|
||||
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
|
||||
ai_assert(0 != (*it)->mNumVertices);
|
||||
ai_assert(0 != (*it)->mNumFaces);
|
||||
|
||||
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
|
||||
(*it)->mNumFaces = (*it)->mNumVertices = 0;
|
||||
|
@ -1151,7 +1111,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
ThrowException("Number of faces is larger than the corresponding color face array");
|
||||
}
|
||||
for (std::vector<aiMesh *>::iterator it = temp->begin() + old; it != temp->end(); ++it) {
|
||||
ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
|
||||
ai_assert(0 != (*it)->mNumVertices);
|
||||
ai_assert(0 != (*it)->mNumFaces);
|
||||
|
||||
(*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
|
||||
(*it)->mNumFaces = (*it)->mNumVertices = 0;
|
||||
|
@ -1171,7 +1132,8 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
vo->b = col->b;
|
||||
vo->a = col->a;
|
||||
}
|
||||
for (unsigned int n = f.mNumIndices; n < 4; ++n);
|
||||
for (unsigned int n = f.mNumIndices; n < 4; ++n)
|
||||
;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->totpoly; ++i) {
|
||||
|
@ -1188,17 +1150,14 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
|
|||
vo->b = ai_real(col.b) * scaleZeroToOne;
|
||||
vo->a = ai_real(col.a) * scaleZeroToOne;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* cam, ConversionData& /*conv_data*/)
|
||||
{
|
||||
aiCamera *BlenderImporter::ConvertCamera(const Scene & /*in*/, const Object *obj, const Camera *cam, ConversionData & /*conv_data*/) {
|
||||
std::unique_ptr<aiCamera> out(new aiCamera());
|
||||
out->mName = obj->id.name + 2;
|
||||
out->mPosition = aiVector3D(0.f, 0.f, 0.f);
|
||||
|
@ -1214,13 +1173,11 @@ aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/)
|
||||
{
|
||||
aiLight *BlenderImporter::ConvertLight(const Scene & /*in*/, const Object *obj, const Lamp *lamp, ConversionData & /*conv_data*/) {
|
||||
std::unique_ptr<aiLight> out(new aiLight());
|
||||
out->mName = obj->id.name + 2;
|
||||
|
||||
switch (lamp->type)
|
||||
{
|
||||
switch (lamp->type) {
|
||||
case Lamp::Type_Local:
|
||||
out->mType = aiLightSource_POINT;
|
||||
break;
|
||||
|
@ -1247,8 +1204,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
|
|||
|
||||
if (lamp->area_shape == 0) {
|
||||
out->mSize = aiVector2D(lamp->area_size, lamp->area_size);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out->mSize = aiVector2D(lamp->area_size, lamp->area_sizey);
|
||||
}
|
||||
|
||||
|
@ -1268,14 +1224,11 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
|
|||
// If default values are supplied, compute the coefficients from light's max distance
|
||||
// Read this: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
||||
//
|
||||
if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f)
|
||||
{
|
||||
if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f) {
|
||||
out->mAttenuationConstant = 1.0f;
|
||||
out->mAttenuationLinear = 2.0f / lamp->dist;
|
||||
out->mAttenuationQuadratic = 1.0f / (lamp->dist * lamp->dist);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
out->mAttenuationConstant = lamp->constant_coefficient;
|
||||
out->mAttenuationLinear = lamp->linear_coefficient;
|
||||
out->mAttenuationQuadratic = lamp->quadratic_coefficient;
|
||||
|
@ -1285,8 +1238,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform)
|
||||
{
|
||||
aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, ConversionData &conv_data, const aiMatrix4x4 &parentTransform) {
|
||||
std::deque<const Object *> children;
|
||||
for (ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end();) {
|
||||
const Object *object = *it;
|
||||
|
@ -1301,12 +1253,10 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
|
|||
|
||||
std::unique_ptr<aiNode> node(new aiNode(obj->id.name + 2)); // skip over the name prefix 'OB'
|
||||
if (obj->data) {
|
||||
switch (obj->type)
|
||||
{
|
||||
switch (obj->type) {
|
||||
case Object ::Type_EMPTY:
|
||||
break; // do nothing
|
||||
|
||||
|
||||
// supported object types
|
||||
case Object ::Type_MESH: {
|
||||
const size_t old = conv_data.meshes->size();
|
||||
|
@ -1319,27 +1269,24 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
|
|||
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||
node->mMeshes[i] = static_cast<unsigned int>(i + old);
|
||||
}
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case Object ::Type_LAMP: {
|
||||
CheckActualType(obj->data.get(), "Lamp");
|
||||
aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>(
|
||||
obj->data.get()),conv_data);
|
||||
aiLight *mesh = ConvertLight(in, obj, static_cast<const Lamp *>(obj->data.get()), conv_data);
|
||||
|
||||
if (mesh) {
|
||||
conv_data.lights->push_back(mesh);
|
||||
}}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case Object ::Type_CAMERA: {
|
||||
CheckActualType(obj->data.get(), "Camera");
|
||||
aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>(
|
||||
obj->data.get()),conv_data);
|
||||
aiCamera *mesh = ConvertCamera(in, obj, static_cast<const Camera *>(obj->data.get()), conv_data);
|
||||
|
||||
if (mesh) {
|
||||
conv_data.cameras->push_back(mesh);
|
||||
}}
|
||||
break;
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
// unsupported object types / log, but do not break
|
||||
case Object ::Type_CURVE:
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -55,7 +55,6 @@ namespace Blender {
|
|||
// 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
|
||||
|
@ -127,7 +126,6 @@ struct ListBase : ElemBase {
|
|||
std::shared_ptr<ElemBase> last;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct PackedFile : ElemBase {
|
||||
int size WARN;
|
||||
|
@ -162,11 +160,8 @@ struct MVert : ElemBase {
|
|||
int mat_nr WARN;
|
||||
int bweight;
|
||||
|
||||
MVert() : ElemBase()
|
||||
, flag(0)
|
||||
, mat_nr(0)
|
||||
, bweight(0)
|
||||
{}
|
||||
MVert() :
|
||||
ElemBase(), flag(0), mat_nr(0), bweight(0) {}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -232,12 +227,8 @@ 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;
|
||||
|
@ -401,18 +392,17 @@ struct CustomDataLayer : ElemBase {
|
|||
char name[64];
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
@ -490,8 +480,8 @@ struct Library : ElemBase {
|
|||
// -------------------------------------------------------------------------------
|
||||
struct Camera : ElemBase {
|
||||
enum Type {
|
||||
Type_PERSP = 0
|
||||
,Type_ORTHO = 1
|
||||
Type_PERSP = 0,
|
||||
Type_ORTHO = 1
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
|
@ -502,24 +492,23 @@ struct Camera : ElemBase {
|
|||
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
|
||||
};
|
||||
|
||||
|
@ -681,18 +670,20 @@ 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;
|
||||
|
@ -709,30 +700,20 @@ struct Object : ElemBase {
|
|||
|
||||
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;
|
||||
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
|
||||
}
|
||||
};
|
||||
|
@ -784,8 +762,8 @@ struct Image : ElemBase {
|
|||
|
||||
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;
|
||||
|
@ -972,12 +947,12 @@ struct MTex : ElemBase {
|
|||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
|
||||
MTex()
|
||||
: ElemBase() {
|
||||
MTex() :
|
||||
ElemBase() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Blender
|
||||
} // namespace Assimp
|
||||
#endif
|
|
@ -43,21 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the TrueSpace COB/SCN importer class.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
||||
#include "COB/COBLoader.h"
|
||||
#include "COB/COBScene.h"
|
||||
#include "AssetLib/COB/COBLoader.h"
|
||||
#include "AssetLib/COB/COBScene.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/LineSplitter.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -65,7 +64,6 @@ using namespace Assimp;
|
|||
using namespace Assimp::COB;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
|
||||
static const float units[] = {
|
||||
1000.f,
|
||||
100.f,
|
||||
|
@ -90,21 +88,17 @@ static const aiImporterDesc desc = {
|
|||
"cob scn"
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
COBImporter::COBImporter()
|
||||
{}
|
||||
COBImporter::COBImporter() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
COBImporter::~COBImporter()
|
||||
{}
|
||||
COBImporter::~COBImporter() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
|
||||
return true;
|
||||
|
@ -119,21 +113,18 @@ bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* COBImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *COBImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void COBImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
void COBImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||
// nothing to be done for the moment
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string& msg)
|
||||
{
|
||||
/*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
|
||||
throw DeadlyImportError("COB: " + msg);
|
||||
}
|
||||
|
||||
|
@ -158,8 +149,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
// load data into intermediate structures
|
||||
if (head[15] == 'A') {
|
||||
ReadAsciiFile(scene, stream.get());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ReadBinaryFile(scene, stream.get());
|
||||
}
|
||||
if (scene.nodes.empty()) {
|
||||
|
@ -193,8 +183,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
for (std::shared_ptr<Node> &n : scene.nodes) {
|
||||
if (n->type == Node::TYPE_LIGHT) {
|
||||
++pScene->mNumLights;
|
||||
}
|
||||
else if (n->type == Node::TYPE_CAMERA) {
|
||||
} else if (n->type == Node::TYPE_CAMERA) {
|
||||
++pScene->mNumCameras;
|
||||
}
|
||||
}
|
||||
|
@ -230,16 +219,14 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertTexture(std::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type)
|
||||
{
|
||||
void ConvertTexture(std::shared_ptr<Texture> tex, aiMaterial *out, aiTextureType type) {
|
||||
const aiString path(tex->path);
|
||||
out->AddProperty(&path, AI_MATKEY_TEXTURE(type, 0));
|
||||
out->AddProperty(&tex->transform, 1, AI_MATKEY_UVTRANSFORM(type, 0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill)
|
||||
{
|
||||
aiNode *COBImporter::BuildNodes(const Node &root, const Scene &scin, aiScene *fill) {
|
||||
aiNode *nd = new aiNode();
|
||||
nd->mName.Set(root.name);
|
||||
nd->mTransformation = root.transform;
|
||||
|
@ -286,15 +273,15 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D(
|
||||
ndmesh.texture_coords[v.uv_idx].x,
|
||||
ndmesh.texture_coords[v.uv_idx].y,
|
||||
0.f
|
||||
);
|
||||
0.f);
|
||||
|
||||
fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++;
|
||||
}
|
||||
}
|
||||
outmesh->mMaterialIndex = fill->mNumMaterials;
|
||||
}{ // create material
|
||||
const Material* min = NULL;
|
||||
}
|
||||
{ // create material
|
||||
const Material *min = nullptr;
|
||||
for (const Material &m : scin.materials) {
|
||||
if (m.parent_id == ndmesh.id && m.matnum == reflist.first) {
|
||||
min = &m;
|
||||
|
@ -303,7 +290,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
std::unique_ptr<const Material> defmat;
|
||||
if (!min) {
|
||||
ASSIMP_LOG_DEBUG(format()<<"Could not resolve material index "
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(format() << "Could not resolve material index "
|
||||
<< reflist.first << " - creating default material for this slot");
|
||||
|
||||
defmat.reset(min = new Material());
|
||||
|
@ -319,9 +306,9 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
mat->AddProperty(&tmp, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
}
|
||||
|
||||
{ int shader;
|
||||
switch(min->shader)
|
||||
{
|
||||
int shader;
|
||||
switch (min->shader) {
|
||||
case Material::FLAT:
|
||||
shader = aiShadingMode_Gouraud;
|
||||
break;
|
||||
|
@ -335,7 +322,9 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
break;
|
||||
|
||||
default:
|
||||
ASSIMP_LOG_ERROR("Unknown option.");
|
||||
ai_assert(false); // shouldn't be here
|
||||
break;
|
||||
}
|
||||
mat->AddProperty(&shader, 1, AI_MATKEY_SHADING_MODEL);
|
||||
if (shader != aiShadingMode_Gouraud) {
|
||||
|
@ -365,8 +354,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Node::TYPE_LIGHT == root.type) {
|
||||
} else if (Node::TYPE_LIGHT == root.type) {
|
||||
const Light &ndlight = (const Light &)(root);
|
||||
aiLight *outlight = fill->mLights[fill->mNumLights++] = new aiLight();
|
||||
|
||||
|
@ -378,8 +366,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
|
||||
// XXX
|
||||
outlight->mType = ndlight.ltype == Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL;
|
||||
}
|
||||
else if (Node::TYPE_CAMERA == root.type) {
|
||||
} else if (Node::TYPE_CAMERA == root.type) {
|
||||
const Camera &ndcam = (const Camera &)(root);
|
||||
aiCamera *outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera();
|
||||
|
||||
|
@ -387,7 +374,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
}
|
||||
|
||||
// add meshes
|
||||
if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0
|
||||
if (nd->mNumMeshes) { // mMeshes must be nullptr if count is 0
|
||||
nd->mMeshes = new unsigned int[nd->mNumMeshes];
|
||||
for (unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||
nd->mMeshes[i] = fill->mNumMeshes - i - 1;
|
||||
|
@ -405,8 +392,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read an ASCII file into the given scene data structure
|
||||
void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
|
||||
{
|
||||
void COBImporter::ReadAsciiFile(Scene &out, StreamReaderLE *stream) {
|
||||
ChunkInfo ci;
|
||||
for (LineSplitter splitter(*stream); splitter; ++splitter) {
|
||||
|
||||
|
@ -456,8 +442,7 @@ void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter)
|
||||
{
|
||||
void COBImporter::ReadChunkInfo_Ascii(ChunkInfo &out, const LineSplitter &splitter) {
|
||||
const char *all_tokens[8];
|
||||
splitter.get_tokens(all_tokens);
|
||||
|
||||
|
@ -468,10 +453,8 @@ void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitt
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name)
|
||||
{
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name <<
|
||||
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
|
||||
void COBImporter::UnsupportedChunk_Ascii(LineSplitter &splitter, const ChunkInfo &nfo, const char *name) {
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
|
||||
|
||||
// we can recover if the chunk size was specified.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
|
@ -483,13 +466,12 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
|
|||
// missing the next line.
|
||||
splitter.get_stream().IncPtr(nfo.size);
|
||||
splitter.swallow_next_increment();
|
||||
}
|
||||
else ThrowException(error);
|
||||
} else
|
||||
ThrowException(error);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
|
||||
{
|
||||
void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, const ChunkInfo & /*nfo*/) {
|
||||
for (; splitter; ++splitter) {
|
||||
if (splitter.match_start("Name")) {
|
||||
msh.name = std::string(splitter[1]);
|
||||
|
@ -497,8 +479,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
|
|||
// make nice names by merging the dupe count
|
||||
std::replace(msh.name.begin(), msh.name.end(),
|
||||
',', '_');
|
||||
}
|
||||
else if (splitter.match_start("Transform")) {
|
||||
} else if (splitter.match_start("Transform")) {
|
||||
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
|
||||
const char *s = splitter->c_str();
|
||||
for (unsigned int x = 0; x < 4; ++x) {
|
||||
|
@ -514,8 +495,7 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, con
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
|
||||
{
|
||||
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in) {
|
||||
const char *rgb = *in;
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
SkipSpaces(&rgb);
|
||||
|
@ -528,8 +508,7 @@ void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadMat1_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Mat1");
|
||||
}
|
||||
|
@ -556,11 +535,9 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
|
||||
if (shader == "metal") {
|
||||
mat.shader = Material::METAL;
|
||||
}
|
||||
else if (shader == "phong") {
|
||||
} else if (shader == "phong") {
|
||||
mat.shader = Material::PHONG;
|
||||
}
|
||||
else if (shader != "flat") {
|
||||
} else if (shader != "flat") {
|
||||
ASSIMP_LOG_WARN_F("Unknown value for `shader` in `Mat1` chunk ", nfo.id);
|
||||
}
|
||||
|
||||
|
@ -588,8 +565,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadUnit_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Unit");
|
||||
}
|
||||
|
@ -606,8 +582,8 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
const unsigned int t = strtoul10(splitter[1]);
|
||||
|
||||
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
|
||||
,1.f):units[t];
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
|
||||
units[t];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -615,16 +591,14 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadChan_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadChan_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Chan");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadLght_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Lght");
|
||||
}
|
||||
|
@ -637,14 +611,11 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
|
||||
if (splitter.match_start("Infinite ")) {
|
||||
msh.ltype = Light::INFINITE;
|
||||
}
|
||||
else if (splitter.match_start("Local ")) {
|
||||
} else if (splitter.match_start("Local ")) {
|
||||
msh.ltype = Light::LOCAL;
|
||||
}
|
||||
else if (splitter.match_start("Spot ")) {
|
||||
} else if (splitter.match_start("Spot ")) {
|
||||
msh.ltype = Light::SPOT;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ASSIMP_LOG_WARN_F("Unknown kind of light source in `Lght` chunk ", nfo.id, " : ", *splitter);
|
||||
msh.ltype = Light::SPOT;
|
||||
}
|
||||
|
@ -675,8 +646,7 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadCame_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Came");
|
||||
}
|
||||
|
@ -693,8 +663,7 @@ void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBone_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 5) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Bone");
|
||||
}
|
||||
|
@ -709,8 +678,7 @@ void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadGrou_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "Grou");
|
||||
}
|
||||
|
@ -723,8 +691,7 @@ void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "PolH");
|
||||
}
|
||||
|
@ -755,8 +722,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
SkipSpaces(&s);
|
||||
v.z = fast_atof(&s);
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("Texture Vertices")) {
|
||||
} else if (splitter.match_start("Texture Vertices")) {
|
||||
const unsigned int cnt = strtoul10(splitter[2]);
|
||||
msh.texture_coords.resize(cnt);
|
||||
|
||||
|
@ -770,8 +736,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
SkipSpaces(&s);
|
||||
v.y = fast_atof(&s);
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("Faces")) {
|
||||
} else if (splitter.match_start("Faces")) {
|
||||
const unsigned int cnt = strtoul10(splitter[1]);
|
||||
msh.faces.reserve(cnt);
|
||||
|
||||
|
@ -813,8 +778,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
if (nfo.version <= 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (splitter.match_start("DrawFlags")) {
|
||||
} else if (splitter.match_start("DrawFlags")) {
|
||||
msh.draw_flags = strtoul10(splitter[1]);
|
||||
break;
|
||||
}
|
||||
|
@ -822,8 +786,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBitM_Ascii(Scene & /*out*/, LineSplitter &splitter, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Ascii(splitter, nfo, "BitM");
|
||||
}
|
||||
|
@ -849,8 +812,7 @@ void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const C
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
|
||||
{
|
||||
void COBImporter::ReadString_Binary(std::string &out, StreamReaderLE &reader) {
|
||||
out.resize(reader.GetI2());
|
||||
for (char &c : out) {
|
||||
c = reader.GetI1();
|
||||
|
@ -858,8 +820,7 @@ void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/)
|
||||
{
|
||||
void COBImporter::ReadBasicNodeInfo_Binary(Node &msh, StreamReaderLE &reader, const ChunkInfo & /*nfo*/) {
|
||||
const unsigned int dupes = reader.GetI2();
|
||||
ReadString_Binary(msh.name, reader);
|
||||
|
||||
|
@ -877,27 +838,23 @@ void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, co
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkInfo& nfo, const char* name)
|
||||
{
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name <<
|
||||
" [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
|
||||
void COBImporter::UnsupportedChunk_Binary(StreamReaderLE &reader, const ChunkInfo &nfo, const char *name) {
|
||||
const std::string error = format("Encountered unsupported chunk: ") << name << " [version: " << nfo.version << ", size: " << nfo.size << "]";
|
||||
|
||||
// we can recover if the chunk size was specified.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
ASSIMP_LOG_ERROR(error);
|
||||
reader.IncPtr(nfo.size);
|
||||
}
|
||||
else ThrowException(error);
|
||||
} else
|
||||
ThrowException(error);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// tiny utility guard to aid me at staying within chunk boundaries.
|
||||
class chunk_guard {
|
||||
public:
|
||||
chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader)
|
||||
: nfo(nfo)
|
||||
, reader(reader)
|
||||
, cur(reader.GetCurrentPos()) {
|
||||
chunk_guard(const COB::ChunkInfo &nfo, StreamReaderLE &reader) :
|
||||
nfo(nfo), reader(reader), cur(reader.GetCurrentPos()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -927,11 +884,7 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
|
||||
while (1) {
|
||||
std::string type;
|
||||
type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
,type += reader -> GetI1()
|
||||
;
|
||||
type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1(), type += reader->GetI1();
|
||||
|
||||
ChunkInfo nfo;
|
||||
nfo.version = reader->GetI2() * 10;
|
||||
|
@ -943,20 +896,15 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
|
||||
if (type == "PolH") {
|
||||
ReadPolH_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "BitM") {
|
||||
} else if (type == "BitM") {
|
||||
ReadBitM_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Grou") {
|
||||
} else if (type == "Grou") {
|
||||
ReadGrou_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Lght") {
|
||||
} else if (type == "Lght") {
|
||||
ReadLght_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Came") {
|
||||
} else if (type == "Came") {
|
||||
ReadCame_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "Mat1") {
|
||||
} else if (type == "Mat1") {
|
||||
ReadMat1_Binary(out, *reader, nfo);
|
||||
}
|
||||
/* else if (type == "Bone") {
|
||||
|
@ -967,24 +915,21 @@ void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
|||
}*/
|
||||
else if (type == "Unit") {
|
||||
ReadUnit_Binary(out, *reader, nfo);
|
||||
}
|
||||
else if (type == "OLay") {
|
||||
} else if (type == "OLay") {
|
||||
// ignore layer index silently.
|
||||
if (nfo.size != static_cast<unsigned int>(-1)) {
|
||||
reader->IncPtr(nfo.size);
|
||||
}
|
||||
else return UnsupportedChunk_Binary(*reader,nfo,type.c_str());
|
||||
}
|
||||
else if (type == "END ") {
|
||||
} else
|
||||
return UnsupportedChunk_Binary(*reader, nfo, type.c_str());
|
||||
} else if (type == "END ") {
|
||||
return;
|
||||
}
|
||||
else UnsupportedChunk_Binary(*reader,nfo,type.c_str());
|
||||
} else
|
||||
UnsupportedChunk_Binary(*reader, nfo, type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadPolH_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "PolH");
|
||||
}
|
||||
|
@ -1023,8 +968,8 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
if (msh.faces.empty()) {
|
||||
ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id);
|
||||
}
|
||||
}
|
||||
else msh.faces.push_back(Face());
|
||||
} else
|
||||
msh.faces.push_back(Face());
|
||||
Face &f = msh.faces.back();
|
||||
|
||||
const size_t num = reader.GetI2();
|
||||
|
@ -1054,8 +999,7 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadBitM_Binary(COB::Scene & /*out*/, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "BitM");
|
||||
}
|
||||
|
@ -1070,8 +1014,7 @@ void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, c
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadMat1_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 8) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Mat1");
|
||||
}
|
||||
|
@ -1172,8 +1115,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadCame_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Came");
|
||||
}
|
||||
|
@ -1195,8 +1137,7 @@ void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadLght_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Lght");
|
||||
}
|
||||
|
@ -1211,8 +1152,7 @@ void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadGrou_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 2) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Grou");
|
||||
}
|
||||
|
@ -1227,8 +1167,7 @@ void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
|
||||
{
|
||||
void COBImporter::ReadUnit_Binary(COB::Scene &out, StreamReaderLE &reader, const ChunkInfo &nfo) {
|
||||
if (nfo.version > 1) {
|
||||
return UnsupportedChunk_Binary(reader, nfo, "Unit");
|
||||
}
|
||||
|
@ -1241,8 +1180,8 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
|
|||
if (nd->id == nfo.parent_id) {
|
||||
const unsigned int t = reader.GetI2();
|
||||
nd->unit_scale = t >= sizeof(units) / sizeof(units[0]) ? (
|
||||
ASSIMP_LOG_WARN_F(t," is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
|
||||
,1.f):units[t];
|
||||
ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id), 1.f) :
|
||||
units[t];
|
||||
|
||||
return;
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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,39 +63,32 @@ 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;
|
|
@ -45,13 +45,13 @@ 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;
|
||||
|
||||
|
@ -59,17 +59,14 @@ 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,8 +76,7 @@ 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_Position,
|
||||
|
@ -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
|
||||
{
|
||||
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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,29 +225,25 @@ struct MeshInstance
|
|||
};
|
||||
|
||||
/** A reference to a camera inside a node*/
|
||||
struct CameraInstance
|
||||
{
|
||||
struct CameraInstance {
|
||||
///< ID of the camera
|
||||
std::string mCamera;
|
||||
};
|
||||
|
||||
/** A reference to a light inside a node*/
|
||||
struct LightInstance
|
||||
{
|
||||
struct LightInstance {
|
||||
///< ID of the camera
|
||||
std::string mLight;
|
||||
};
|
||||
|
||||
/** A reference to a node inside a node*/
|
||||
struct NodeInstance
|
||||
{
|
||||
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;
|
||||
|
@ -288,8 +269,8 @@ struct Node
|
|||
std::string mPrimaryCamera;
|
||||
|
||||
//! Constructor. Begin with a zero parent
|
||||
Node()
|
||||
: mParent( nullptr ){
|
||||
Node() :
|
||||
mParent(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -301,16 +282,14 @@ struct Node
|
|||
};
|
||||
|
||||
/** 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
|
||||
{
|
||||
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
|
||||
|
@ -319,49 +298,54 @@ struct Accessor
|
|||
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
|
||||
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
|
||||
{
|
||||
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()
|
||||
{
|
||||
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...
|
||||
|
@ -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;
|
||||
|
||||
|
@ -443,29 +425,25 @@ struct Controller
|
|||
};
|
||||
|
||||
/** 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,8 +513,7 @@ 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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -632,19 +603,16 @@ struct Animation
|
|||
std::vector<Animation *> mSubAnims;
|
||||
|
||||
/** Destructor */
|
||||
~Animation()
|
||||
{
|
||||
~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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
|
||||
Animation *pAnim = (*it);
|
||||
|
||||
pAnim->CollectChannelsRecursively(channels);
|
||||
|
@ -652,18 +620,15 @@ struct Animation
|
|||
}
|
||||
|
||||
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
|
||||
void CombineSingleChannelAnimations()
|
||||
{
|
||||
void CombineSingleChannelAnimations() {
|
||||
CombineSingleChannelAnimationsRecursively(this);
|
||||
}
|
||||
|
||||
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
|
||||
{
|
||||
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();)
|
||||
{
|
||||
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
|
||||
Animation *anim = *it;
|
||||
CombineSingleChannelAnimationsRecursively(anim);
|
||||
|
||||
|
@ -678,10 +643,8 @@ struct Animation
|
|||
}
|
||||
|
||||
// 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();)
|
||||
{
|
||||
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]);
|
||||
|
@ -696,8 +659,7 @@ struct Animation
|
|||
};
|
||||
|
||||
/** Description of a collada animation channel which has been determined to affect the current node */
|
||||
struct ChannelEntry
|
||||
{
|
||||
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
|
||||
|
@ -710,15 +672,14 @@ struct ChannelEntry
|
|||
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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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);
|
|
@ -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" );
|
||||
}
|
||||
|
|
@ -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,9 +58,8 @@ namespace FBX {
|
|||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
|
||||
: Object(id, element, name)
|
||||
{
|
||||
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");
|
||||
|
@ -89,19 +88,15 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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 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
|
||||
|
@ -136,8 +131,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
|
|||
continue;
|
||||
}
|
||||
|
||||
// XXX support constraints as DOM class
|
||||
//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
|
||||
target = ob;
|
||||
if (!target) {
|
||||
continue;
|
||||
|
@ -155,14 +148,12 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::~AnimationCurveNode()
|
||||
{
|
||||
AnimationCurveNode::~AnimationCurveNode() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveMap& AnimationCurveNode::Curves() const
|
||||
{
|
||||
const AnimationCurveMap &AnimationCurveNode::Curves() const {
|
||||
if (curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
|
||||
|
@ -175,13 +166,13 @@ const AnimationCurveMap& AnimationCurveNode::Curves() const
|
|||
}
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
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) {
|
||||
if (nullptr == anim) {
|
||||
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
|
||||
continue;
|
||||
}
|
||||
|
@ -194,10 +185,8 @@ 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)
|
||||
{
|
||||
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
|
||||
|
@ -205,15 +194,13 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::s
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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
|
||||
|
@ -259,9 +246,8 @@ 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)
|
||||
{
|
||||
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
|
||||
|
@ -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
|
|
@ -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 {
|
||||
|
@ -427,6 +428,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
|
||||
{
|
||||
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 ) {
|
|
@ -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()) {
|
|
@ -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
|
|
@ -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;
|
|
@ -96,7 +96,7 @@ public:
|
|||
template <typename T>
|
||||
const T* Get(bool dieOnError = false) {
|
||||
const Object* const ob = Get(dieOnError);
|
||||
return ob ? dynamic_cast<const T*>(ob) : NULL;
|
||||
return ob ? dynamic_cast<const T *>(ob) : nullptr;
|
||||
}
|
||||
|
||||
uint64_t ID() const {
|
||||
|
@ -213,7 +213,8 @@ private:
|
|||
type name() const { \
|
||||
const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
|
||||
if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
|
||||
ai_assert(static_cast<int>(default_value) >= 0 && static_cast<int>(default_value) < AI_CONCAT(type, _MAX)); \
|
||||
ai_assert(static_cast<int>(default_value) >= 0); \
|
||||
ai_assert(static_cast<int>(default_value) < AI_CONCAT(type, _MAX)); \
|
||||
return static_cast<type>(default_value); \
|
||||
} \
|
||||
return static_cast<type>(ival); \
|
||||
|
@ -744,7 +745,7 @@ public:
|
|||
wants animations for. If the curve node does not match one of these, std::range_error
|
||||
will be thrown. */
|
||||
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);
|
||||
const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
|
||||
|
||||
virtual ~AnimationCurveNode();
|
||||
|
||||
|
@ -756,7 +757,7 @@ public:
|
|||
|
||||
const AnimationCurveMap& Curves() const;
|
||||
|
||||
/** Object the curve is assigned to, this can be NULL if the
|
||||
/** Object the curve is assigned to, this can be nullptr if the
|
||||
* target object has no DOM representation or could not
|
||||
* be read for other reasons.*/
|
||||
const Object* Target() const {
|
||||
|
@ -968,7 +969,7 @@ public:
|
|||
|
||||
// note: a connection ensures that the source and dest objects exist, but
|
||||
// not that they have DOM representations, so the return value of one of
|
||||
// these functions can still be NULL.
|
||||
// these functions can still be nullptr.
|
||||
const Object* SourceObject() const;
|
||||
const Object* DestinationObject() const;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue